@samitouri / QOS-React-2 / commits / f2b62e9d90

Warn when both value and defaultValue or both check and defaultChecked props are specified on input, textarea, or select elements

Michael McDermott committed Jan 11, 2016 at 18:09 UTC f2b62e9d903b2144cbd3b979e30c316ee287f5a1
6 files changed +126
src/renderers/dom/client/wrappers/ReactDOMInput.js
+24
@@ -25,6 +25,8 @@ var instancesByReactID = {};
25 var didWarnValueLink = false;
26 var didWarnCheckedLink = false;
27 var didWarnValueNull = false;
28 +var didWarnValueDefaultValue = false;
29 +var didWarnCheckedDefaultChecked = false;
30
31 function forceUpdateIfMounted() {
32 if (this._rootNodeID) {
@@ -104,6 +106,28 @@ var ReactDOMInput = {
106 );
107 didWarnCheckedLink = true;
108 }
109 + if (props.checked !== undefined && props.defaultChecked !== undefined &&
110 + !didWarnCheckedDefaultChecked) {
111 + warning(
112 + false,
113 + 'Input elements must be either controlled or uncontrolled (specify either the ' +
114 + 'checked prop, or the defaultChecked prop, but not both). Decide between using a ' +
115 + 'controlled or uncontrolled input and remove one of these props. More info: ' +
116 + 'https://fb.me/react-controlled-components'
117 + );
118 + didWarnCheckedDefaultChecked = true;
119 + }
120 + if (props.value !== undefined && props.defaultValue !== undefined &&
121 + !didWarnValueDefaultValue) {
122 + warning(
123 + false,
124 + 'Input elements must be either controlled or uncontrolled (specify either the value ' +
125 + 'prop, or the defaultValue prop, but not both). Decide between using a controlled ' +
126 + 'or uncontrolled input and remove one of these props. More info: ' +
127 + 'https://fb.me/react-controlled-components'
128 + );
129 + didWarnValueDefaultValue = true;
130 + }
131 warnIfValueIsNull(props);
132 }
133
src/renderers/dom/client/wrappers/ReactDOMSelect.js
+13
@@ -20,6 +20,7 @@ var warning = require('warning');
20
21 var didWarnValueLink = false;
22 var didWarnValueNull = false;
23 +var didWarnValueDefaultValue = false;
24
25 function updateOptionsIfPendingUpdateAndMounted() {
26 if (this._rootNodeID && this._wrapperState.pendingUpdate) {
@@ -178,6 +179,18 @@ var ReactDOMSelect = {
179 onChange: _handleChange.bind(inst),
180 wasMultiple: Boolean(props.multiple),
181 };
182 +
183 + if (props.value !== undefined && props.defaultValue !== undefined &&
184 + !didWarnValueDefaultValue) {
185 + warning(
186 + false,
187 + 'Select elements must be either controlled or uncontrolled (specify either the ' +
188 + 'value prop, or the defaultValue prop, but not both). Decide between using a ' +
189 + 'controlled or uncontrolled select element and remove one of these props. More info: ' +
190 + 'https://fb.me/react-controlled-components'
191 + );
192 + didWarnValueDefaultValue = true;
193 + }
194 },
195
196 getSelectValueContext: function(inst) {
src/renderers/dom/client/wrappers/ReactDOMTextarea.js
+11
@@ -22,6 +22,7 @@ var warning = require('warning');
22
23 var didWarnValueLink = false;
24 var didWarnValueNull = false;
25 +var didWarnValDefaultVal = false;
26
27 function forceUpdateIfMounted() {
28 if (this._rootNodeID) {
@@ -91,6 +92,16 @@ var ReactDOMTextarea = {
92 );
93 didWarnValueLink = true;
94 }
95 + if (props.value !== undefined && props.defaultValue !== undefined && !didWarnValDefaultVal) {
96 + warning(
97 + false,
98 + 'Textarea elements must be either controlled or uncontrolled (specify either the value ' +
99 + 'prop, or the defaultValue prop, but not both). Decide between using a controlled or ' +
100 + 'uncontrolled input and remove one of these props. More info: ' +
101 + 'https://fb.me/react-controlled-components'
102 + );
103 + didWarnValDefaultVal = true;
104 + }
105 warnIfValueIsNull(props);
106 }
107
src/renderers/dom/client/wrappers/__tests__/ReactDOMInput-test.js
+34
@@ -415,6 +415,40 @@ describe('ReactDOMInput', function() {
415 expect(console.error.argsForCall.length).toBe(1);
416 });
417
418 + it('should throw warning message if checked and defaultChecked props are specified', function() {
419 + ReactTestUtils.renderIntoDocument(
420 + <input type="radio" checked={true} defaultChecked={true} readOnly={true} />
421 + );
422 + expect(console.error.argsForCall[0][0]).toContain(
423 + 'Input elements must be either controlled or uncontrolled (specify either the ' +
424 + 'checked prop, or the defaultChecked prop, but not both). Decide between using a ' +
425 + 'controlled or uncontrolled input and remove one of these props. More info: ' +
426 + 'https://fb.me/react-controlled-components'
427 + );
428 +
429 + ReactTestUtils.renderIntoDocument(
430 + <input type="radio" checked={true} defaultChecked={true} readOnly={true} />
431 + );
432 + expect(console.error.argsForCall.length).toBe(1);
433 + });
434 +
435 + it('should throw warning message if value and defaultValue props are specified', function() {
436 + ReactTestUtils.renderIntoDocument(
437 + <input type="text" value="foo" defaultValue="bar" readOnly={true} />
438 + );
439 + expect(console.error.argsForCall[0][0]).toContain(
440 + 'Input elements must be either controlled or uncontrolled (specify either the value ' +
441 + 'prop, or the defaultValue prop, but not both). Decide between using a controlled or ' +
442 + 'uncontrolled input and remove one of these props. More info: ' +
443 + 'https://fb.me/react-controlled-components'
444 + );
445 +
446 + ReactTestUtils.renderIntoDocument(
447 + <input type="text" value="foo" defaultValue="bar" readOnly={true} />
448 + );
449 + expect(console.error.argsForCall.length).toBe(1);
450 + });
451 +
452 it('sets type before value always', function() {
453 var log = [];
454 var originalCreateElement = document.createElement;
src/renderers/dom/client/wrappers/__tests__/ReactDOMSelect-test.js
+26
@@ -490,4 +490,30 @@ describe('ReactDOMSelect', function() {
490
491 expect(node.value).toBe('giraffe');
492 });
493 +
494 + it('should throw warning message if value and defaultValue props are specified', function() {
495 + spyOn(console, 'error');
496 + ReactTestUtils.renderIntoDocument(
497 + <select value="giraffe" defaultValue="giraffe" readOnly={true}>
498 + <option value="monkey">A monkey!</option>
499 + <option value="giraffe">A giraffe!</option>
500 + <option value="gorilla">A gorilla!</option>
501 + </select>
502 + );
503 + expect(console.error.argsForCall[0][0]).toContain(
504 + 'Select elements must be either controlled or uncontrolled (specify either the ' +
505 + 'value prop, or the defaultValue prop, but not both). Decide between using a ' +
506 + 'controlled or uncontrolled select element and remove one of these props. More info: ' +
507 + 'https://fb.me/react-controlled-components'
508 + );
509 +
510 + ReactTestUtils.renderIntoDocument(
511 + <select value="giraffe" defaultValue="giraffe" readOnly={true}>
512 + <option value="monkey">A monkey!</option>
513 + <option value="giraffe">A giraffe!</option>
514 + <option value="gorilla">A gorilla!</option>
515 + </select>
516 + );
517 + expect(console.error.argsForCall.length).toBe(1);
518 + });
519 });
src/renderers/dom/client/wrappers/__tests__/ReactDOMTextarea-test.js
+18
@@ -278,4 +278,22 @@ describe('ReactDOMTextarea', function() {
278 ReactTestUtils.renderIntoDocument(<textarea value={null} />);
279 expect(console.error.argsForCall.length).toBe(1);
280 });
281 +
282 + it('should throw warning message if value and defaultValue are specified', function() {
283 + spyOn(console, 'error');
284 + ReactTestUtils.renderIntoDocument(
285 + <textarea value="foo" defaultValue="bar" readOnly={true} />
286 + );
287 + expect(console.error.argsForCall[0][0]).toContain(
288 + 'Textarea elements must be either controlled or uncontrolled (specify either the value ' +
289 + 'prop, or the defaultValue prop, but not both). Decide between using a controlled or ' +
290 + 'uncontrolled input and remove one of these props. More info: ' +
291 + 'https://fb.me/react-controlled-components'
292 + );
293 +
294 + ReactTestUtils.renderIntoDocument(
295 + <textarea value="foo" defaultValue="bar" readOnly={true} />
296 + );
297 + expect(console.error.argsForCall.length).toBe(1);
298 + });
299 });