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
});