diff --git a/src/renderers/dom/client/wrappers/ReactDOMInput.js b/src/renderers/dom/client/wrappers/ReactDOMInput.js index dfa860a2db..4350b4b050 100644 --- a/src/renderers/dom/client/wrappers/ReactDOMInput.js +++ b/src/renderers/dom/client/wrappers/ReactDOMInput.js @@ -36,7 +36,7 @@ function forceUpdateIfMounted() { function isControlled(props) { var usesChecked = props.type === 'checkbox' || props.type === 'radio'; - return usesChecked ? props.checked !== undefined : props.value !== undefined; + return usesChecked ? props.checked != null : props.value != null; } /** diff --git a/src/renderers/dom/client/wrappers/__tests__/ReactDOMInput-test.js b/src/renderers/dom/client/wrappers/__tests__/ReactDOMInput-test.js index 342d96e194..0195802484 100644 --- a/src/renderers/dom/client/wrappers/__tests__/ReactDOMInput-test.js +++ b/src/renderers/dom/client/wrappers/__tests__/ReactDOMInput-test.js @@ -571,7 +571,7 @@ describe('ReactDOMInput', function() { expect(console.error.calls.count()).toBe(1); }); - it('should warn if controlled input switches to uncontrolled', function() { + it('should warn if controlled input switches to uncontrolled (value is undefined)', function() { var stub = ; var container = document.createElement('div'); ReactDOM.render(stub, container); @@ -585,6 +585,20 @@ describe('ReactDOMInput', function() { ); }); + it('should warn if controlled input switches to uncontrolled (value is null)', function() { + var stub = ; + var container = document.createElement('div'); + ReactDOM.render(stub, container); + ReactDOM.render(, container); + expect(console.error.calls.count()).toBeGreaterThan(0); + expect(console.error.calls.argsFor(1)[0]).toContain( + 'A component is changing a controlled input of type text to be uncontrolled. ' + + 'Input elements should not switch from controlled to uncontrolled (or vice versa). ' + + 'Decide between using a controlled or uncontrolled input ' + + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components' + ); + }); + it('should warn if controlled input switches to uncontrolled with defaultValue', function() { var stub = ; var container = document.createElement('div'); @@ -599,7 +613,7 @@ describe('ReactDOMInput', function() { ); }); - it('should warn if uncontrolled input switches to controlled', function() { + it('should warn if uncontrolled input (value is undefined) switches to controlled', function() { var stub = ; var container = document.createElement('div'); ReactDOM.render(stub, container); @@ -613,7 +627,21 @@ describe('ReactDOMInput', function() { ); }); - it('should warn if controlled checkbox switches to uncontrolled', function() { + it('should warn if uncontrolled input (value is null) switches to controlled', function() { + var stub = ; + var container = document.createElement('div'); + ReactDOM.render(stub, container); + ReactDOM.render(, container); + expect(console.error.calls.count()).toBeGreaterThan(0); + expect(console.error.calls.argsFor(1)[0]).toContain( + 'A component is changing an uncontrolled input of type text to be controlled. ' + + 'Input elements should not switch from uncontrolled to controlled (or vice versa). ' + + 'Decide between using a controlled or uncontrolled input ' + + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components' + ); + }); + + it('should warn if controlled checkbox switches to uncontrolled (checked is undefined)', function() { var stub = ; var container = document.createElement('div'); ReactDOM.render(stub, container); @@ -627,6 +655,20 @@ describe('ReactDOMInput', function() { ); }); + it('should warn if controlled checkbox switches to uncontrolled (checked is null)', function() { + var stub = ; + var container = document.createElement('div'); + ReactDOM.render(stub, container); + ReactDOM.render(, container); + expect(console.error.calls.count()).toBe(1); + expect(console.error.calls.argsFor(0)[0]).toContain( + 'A component is changing a controlled input of type checkbox to be uncontrolled. ' + + 'Input elements should not switch from controlled to uncontrolled (or vice versa). ' + + 'Decide between using a controlled or uncontrolled input ' + + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components' + ); + }); + it('should warn if controlled checkbox switches to uncontrolled with defaultChecked', function() { var stub = ; var container = document.createElement('div'); @@ -641,7 +683,7 @@ describe('ReactDOMInput', function() { ); }); - it('should warn if uncontrolled checkbox switches to controlled', function() { + it('should warn if uncontrolled checkbox (checked is undefined) switches to controlled', function() { var stub = ; var container = document.createElement('div'); ReactDOM.render(stub, container); @@ -655,7 +697,21 @@ describe('ReactDOMInput', function() { ); }); - it('should warn if controlled radio switches to uncontrolled', function() { + it('should warn if uncontrolled checkbox (checked is null) switches to controlled', function() { + var stub = ; + var container = document.createElement('div'); + ReactDOM.render(stub, container); + ReactDOM.render(, container); + expect(console.error.calls.count()).toBe(1); + expect(console.error.calls.argsFor(0)[0]).toContain( + 'A component is changing an uncontrolled input of type checkbox to be controlled. ' + + 'Input elements should not switch from uncontrolled to controlled (or vice versa). ' + + 'Decide between using a controlled or uncontrolled input ' + + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components' + ); + }); + + it('should warn if controlled radio switches to uncontrolled (checked is undefined)', function() { var stub = ; var container = document.createElement('div'); ReactDOM.render(stub, container); @@ -669,6 +725,20 @@ describe('ReactDOMInput', function() { ); }); + it('should warn if controlled radio switches to uncontrolled (checked is null)', function() { + var stub = ; + var container = document.createElement('div'); + ReactDOM.render(stub, container); + ReactDOM.render(, container); + expect(console.error.calls.count()).toBe(1); + expect(console.error.calls.argsFor(0)[0]).toContain( + 'A component is changing a controlled input of type radio to be uncontrolled. ' + + 'Input elements should not switch from controlled to uncontrolled (or vice versa). ' + + 'Decide between using a controlled or uncontrolled input ' + + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components' + ); + }); + it('should warn if controlled radio switches to uncontrolled with defaultChecked', function() { var stub = ; var container = document.createElement('div'); @@ -683,7 +753,7 @@ describe('ReactDOMInput', function() { ); }); - it('should warn if uncontrolled radio switches to controlled', function() { + it('should warn if uncontrolled radio (checked is undefined) switches to controlled', function() { var stub = ; var container = document.createElement('div'); ReactDOM.render(stub, container); @@ -697,6 +767,20 @@ describe('ReactDOMInput', function() { ); }); + it('should warn if uncontrolled radio (checked is null) switches to controlled', function() { + var stub = ; + var container = document.createElement('div'); + ReactDOM.render(stub, container); + ReactDOM.render(, container); + expect(console.error.calls.count()).toBe(1); + expect(console.error.calls.argsFor(0)[0]).toContain( + 'A component is changing an uncontrolled input of type radio to be controlled. ' + + 'Input elements should not switch from uncontrolled to controlled (or vice versa). ' + + 'Decide between using a controlled or uncontrolled input ' + + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components' + ); + }); + it('should not warn if radio value changes but never becomes controlled', function() { var container = document.createElement('div'); ReactDOM.render(, container);