Skip to content

Commit

Permalink
Warn if input changes controlledness - also for null (#7544) (#7603)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcin-mazurek authored and jimfb committed Aug 29, 2016
1 parent 5331fd0 commit ba84b5b
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 7 deletions.
2 changes: 1 addition & 1 deletion src/renderers/dom/client/wrappers/ReactDOMInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/**
Expand Down
96 changes: 90 additions & 6 deletions src/renderers/dom/client/wrappers/__tests__/ReactDOMInput-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,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 = <input type="text" value="controlled" onChange={emptyFunction} />;
var container = document.createElement('div');
ReactDOM.render(stub, container);
Expand All @@ -594,6 +594,20 @@ describe('ReactDOMInput', function() {
);
});

it('should warn if controlled input switches to uncontrolled (value is null)', function() {
var stub = <input type="text" value="controlled" onChange={emptyFunction} />;
var container = document.createElement('div');
ReactDOM.render(stub, container);
ReactDOM.render(<input type="text" value={null} />, 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 = <input type="text" value="controlled" onChange={emptyFunction} />;
var container = document.createElement('div');
Expand All @@ -608,7 +622,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 = <input type="text" />;
var container = document.createElement('div');
ReactDOM.render(stub, container);
Expand All @@ -622,7 +636,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 = <input type="text" value={null} />;
var container = document.createElement('div');
ReactDOM.render(stub, container);
ReactDOM.render(<input type="text" value="controlled" />, 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 = <input type="checkbox" checked={true} onChange={emptyFunction} />;
var container = document.createElement('div');
ReactDOM.render(stub, container);
Expand All @@ -636,6 +664,20 @@ describe('ReactDOMInput', function() {
);
});

it('should warn if controlled checkbox switches to uncontrolled (checked is null)', function() {
var stub = <input type="checkbox" checked={true} onChange={emptyFunction} />;
var container = document.createElement('div');
ReactDOM.render(stub, container);
ReactDOM.render(<input type="checkbox" checked={null} />, 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 = <input type="checkbox" checked={true} onChange={emptyFunction} />;
var container = document.createElement('div');
Expand All @@ -650,7 +692,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 = <input type="checkbox" />;
var container = document.createElement('div');
ReactDOM.render(stub, container);
Expand All @@ -664,7 +706,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 = <input type="checkbox" checked={null} />;
var container = document.createElement('div');
ReactDOM.render(stub, container);
ReactDOM.render(<input type="checkbox" checked={true} />, 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 = <input type="radio" checked={true} onChange={emptyFunction} />;
var container = document.createElement('div');
ReactDOM.render(stub, container);
Expand All @@ -678,6 +734,20 @@ describe('ReactDOMInput', function() {
);
});

it('should warn if controlled radio switches to uncontrolled (checked is null)', function() {
var stub = <input type="radio" checked={true} onChange={emptyFunction} />;
var container = document.createElement('div');
ReactDOM.render(stub, container);
ReactDOM.render(<input type="radio" checked={null} />, 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 = <input type="radio" checked={true} onChange={emptyFunction} />;
var container = document.createElement('div');
Expand All @@ -692,7 +762,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 = <input type="radio" />;
var container = document.createElement('div');
ReactDOM.render(stub, container);
Expand All @@ -706,6 +776,20 @@ describe('ReactDOMInput', function() {
);
});

it('should warn if uncontrolled radio (checked is null) switches to controlled', function() {
var stub = <input type="radio" checked={null} />;
var container = document.createElement('div');
ReactDOM.render(stub, container);
ReactDOM.render(<input type="radio" checked={true} />, 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(<input type="radio" value="value" />, container);
Expand Down

0 comments on commit ba84b5b

Please sign in to comment.