@samitouri / QOS-React / commits / ba84b5b0a7

Warn if input changes controlledness - also for null (#7544) (#7603)

Marcin Mazurek committed Aug 29, 2016 at 19:23 UTC ba84b5b0a7047115e60a8fc68d563782a5756fba
2 files changed +91 -7
src/renderers/dom/client/wrappers/ReactDOMInput.js
+1 -1
@@ -36,7 +36,7 @@ function forceUpdateIfMounted() {
36
37 function isControlled(props) {
38 var usesChecked = props.type === 'checkbox' || props.type === 'radio';
39 - return usesChecked ? props.checked !== undefined : props.value !== undefined;
39 + return usesChecked ? props.checked != null : props.value != null;
40 }
41
42 /**
src/renderers/dom/client/wrappers/__tests__/ReactDOMInput-test.js
+90 -6
@@ -580,7 +580,7 @@ describe('ReactDOMInput', function() {
580 expect(console.error.calls.count()).toBe(1);
581 });
582
583 - it('should warn if controlled input switches to uncontrolled', function() {
583 + it('should warn if controlled input switches to uncontrolled (value is undefined)', function() {
584 var stub = <input type="text" value="controlled" onChange={emptyFunction} />;
585 var container = document.createElement('div');
586 ReactDOM.render(stub, container);
@@ -594,6 +594,20 @@ describe('ReactDOMInput', function() {
594 );
595 });
596
597 + it('should warn if controlled input switches to uncontrolled (value is null)', function() {
598 + var stub = <input type="text" value="controlled" onChange={emptyFunction} />;
599 + var container = document.createElement('div');
600 + ReactDOM.render(stub, container);
601 + ReactDOM.render(<input type="text" value={null} />, container);
602 + expect(console.error.calls.count()).toBeGreaterThan(0);
603 + expect(console.error.calls.argsFor(1)[0]).toContain(
604 + 'A component is changing a controlled input of type text to be uncontrolled. ' +
605 + 'Input elements should not switch from controlled to uncontrolled (or vice versa). ' +
606 + 'Decide between using a controlled or uncontrolled input ' +
607 + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components'
608 + );
609 + });
610 +
611 it('should warn if controlled input switches to uncontrolled with defaultValue', function() {
612 var stub = <input type="text" value="controlled" onChange={emptyFunction} />;
613 var container = document.createElement('div');
@@ -608,7 +622,7 @@ describe('ReactDOMInput', function() {
622 );
623 });
624
611 - it('should warn if uncontrolled input switches to controlled', function() {
625 + it('should warn if uncontrolled input (value is undefined) switches to controlled', function() {
626 var stub = <input type="text" />;
627 var container = document.createElement('div');
628 ReactDOM.render(stub, container);
@@ -622,7 +636,21 @@ describe('ReactDOMInput', function() {
636 );
637 });
638
625 - it('should warn if controlled checkbox switches to uncontrolled', function() {
639 + it('should warn if uncontrolled input (value is null) switches to controlled', function() {
640 + var stub = <input type="text" value={null} />;
641 + var container = document.createElement('div');
642 + ReactDOM.render(stub, container);
643 + ReactDOM.render(<input type="text" value="controlled" />, container);
644 + expect(console.error.calls.count()).toBeGreaterThan(0);
645 + expect(console.error.calls.argsFor(1)[0]).toContain(
646 + 'A component is changing an uncontrolled input of type text to be controlled. ' +
647 + 'Input elements should not switch from uncontrolled to controlled (or vice versa). ' +
648 + 'Decide between using a controlled or uncontrolled input ' +
649 + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components'
650 + );
651 + });
652 +
653 + it('should warn if controlled checkbox switches to uncontrolled (checked is undefined)', function() {
654 var stub = <input type="checkbox" checked={true} onChange={emptyFunction} />;
655 var container = document.createElement('div');
656 ReactDOM.render(stub, container);
@@ -636,6 +664,20 @@ describe('ReactDOMInput', function() {
664 );
665 });
666
667 + it('should warn if controlled checkbox switches to uncontrolled (checked is null)', function() {
668 + var stub = <input type="checkbox" checked={true} onChange={emptyFunction} />;
669 + var container = document.createElement('div');
670 + ReactDOM.render(stub, container);
671 + ReactDOM.render(<input type="checkbox" checked={null} />, container);
672 + expect(console.error.calls.count()).toBe(1);
673 + expect(console.error.calls.argsFor(0)[0]).toContain(
674 + 'A component is changing a controlled input of type checkbox to be uncontrolled. ' +
675 + 'Input elements should not switch from controlled to uncontrolled (or vice versa). ' +
676 + 'Decide between using a controlled or uncontrolled input ' +
677 + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components'
678 + );
679 + });
680 +
681 it('should warn if controlled checkbox switches to uncontrolled with defaultChecked', function() {
682 var stub = <input type="checkbox" checked={true} onChange={emptyFunction} />;
683 var container = document.createElement('div');
@@ -650,7 +692,7 @@ describe('ReactDOMInput', function() {
692 );
693 });
694
653 - it('should warn if uncontrolled checkbox switches to controlled', function() {
695 + it('should warn if uncontrolled checkbox (checked is undefined) switches to controlled', function() {
696 var stub = <input type="checkbox" />;
697 var container = document.createElement('div');
698 ReactDOM.render(stub, container);
@@ -664,7 +706,21 @@ describe('ReactDOMInput', function() {
706 );
707 });
708
667 - it('should warn if controlled radio switches to uncontrolled', function() {
709 + it('should warn if uncontrolled checkbox (checked is null) switches to controlled', function() {
710 + var stub = <input type="checkbox" checked={null} />;
711 + var container = document.createElement('div');
712 + ReactDOM.render(stub, container);
713 + ReactDOM.render(<input type="checkbox" checked={true} />, container);
714 + expect(console.error.calls.count()).toBe(1);
715 + expect(console.error.calls.argsFor(0)[0]).toContain(
716 + 'A component is changing an uncontrolled input of type checkbox to be controlled. ' +
717 + 'Input elements should not switch from uncontrolled to controlled (or vice versa). ' +
718 + 'Decide between using a controlled or uncontrolled input ' +
719 + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components'
720 + );
721 + });
722 +
723 + it('should warn if controlled radio switches to uncontrolled (checked is undefined)', function() {
724 var stub = <input type="radio" checked={true} onChange={emptyFunction} />;
725 var container = document.createElement('div');
726 ReactDOM.render(stub, container);
@@ -678,6 +734,20 @@ describe('ReactDOMInput', function() {
734 );
735 });
736
737 + it('should warn if controlled radio switches to uncontrolled (checked is null)', function() {
738 + var stub = <input type="radio" checked={true} onChange={emptyFunction} />;
739 + var container = document.createElement('div');
740 + ReactDOM.render(stub, container);
741 + ReactDOM.render(<input type="radio" checked={null} />, container);
742 + expect(console.error.calls.count()).toBe(1);
743 + expect(console.error.calls.argsFor(0)[0]).toContain(
744 + 'A component is changing a controlled input of type radio to be uncontrolled. ' +
745 + 'Input elements should not switch from controlled to uncontrolled (or vice versa). ' +
746 + 'Decide between using a controlled or uncontrolled input ' +
747 + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components'
748 + );
749 + });
750 +
751 it('should warn if controlled radio switches to uncontrolled with defaultChecked', function() {
752 var stub = <input type="radio" checked={true} onChange={emptyFunction} />;
753 var container = document.createElement('div');
@@ -692,7 +762,7 @@ describe('ReactDOMInput', function() {
762 );
763 });
764
695 - it('should warn if uncontrolled radio switches to controlled', function() {
765 + it('should warn if uncontrolled radio (checked is undefined) switches to controlled', function() {
766 var stub = <input type="radio" />;
767 var container = document.createElement('div');
768 ReactDOM.render(stub, container);
@@ -706,6 +776,20 @@ describe('ReactDOMInput', function() {
776 );
777 });
778
779 + it('should warn if uncontrolled radio (checked is null) switches to controlled', function() {
780 + var stub = <input type="radio" checked={null} />;
781 + var container = document.createElement('div');
782 + ReactDOM.render(stub, container);
783 + ReactDOM.render(<input type="radio" checked={true} />, container);
784 + expect(console.error.calls.count()).toBe(1);
785 + expect(console.error.calls.argsFor(0)[0]).toContain(
786 + 'A component is changing an uncontrolled input of type radio to be controlled. ' +
787 + 'Input elements should not switch from uncontrolled to controlled (or vice versa). ' +
788 + 'Decide between using a controlled or uncontrolled input ' +
789 + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components'
790 + );
791 + });
792 +
793 it('should not warn if radio value changes but never becomes controlled', function() {
794 var container = document.createElement('div');
795 ReactDOM.render(<input type="radio" value="value" />, container);