Issue: 5013 Added necessary code for firing warning if value is null
Fixed the lint issues Added logic for handling the warning only once and added the test cases for the same. Also moved the warning part to only DEV mode Changed few lines related to the formatting issues Removing the empty whitespace
Ants committed
Oct 4, 2015 at 11:58 UTC
b42c1dafcc651b358b4add11a948eeab38d987db
6 files changed
+94
-1
src/renderers/dom/client/wrappers/ReactDOMInput.js
+19
@@ -24,6 +24,7 @@ var instancesByReactID = {};
24
25
var didWarnValueLink = false;
26
var didWarnCheckedLink = false;
27
+var didWarnValueNull = false;
28
29
function forceUpdateIfMounted() {
30
if (this._rootNodeID) {
@@ -32,6 +33,19 @@ function forceUpdateIfMounted() {
33
}
34
}
35
36
+function warnIfValueIsNull(props) {
37
+ if (props != null && props.value === null && !didWarnValueNull) {
38
+ warning(
39
+ false,
40
+ '`value` prop on `input` should not be null. ' +
41
+ 'Consider using the empty string to clear the component or' +
42
+ ' `undefined` for uncontrolled components.'
43
+ );
44
+
45
+ didWarnValueNull = true;
46
+ }
47
+}
48
+
49
/**
50
* Implements an <input> native component that allows setting these optional
51
* props: `checked`, `value`, `defaultChecked`, and `defaultValue`.
@@ -86,6 +100,7 @@ var ReactDOMInput = {
100
);
101
didWarnCheckedLink = true;
102
}
103
+ warnIfValueIsNull(props);
104
}
105
106
var defaultValue = props.defaultValue;
@@ -108,6 +123,10 @@ var ReactDOMInput = {
123
updateWrapper: function(inst) {
124
var props = inst._currentElement.props;
125
126
+ if (__DEV__) {
127
+ warnIfValueIsNull(props);
128
+ }
129
+
130
// TODO: Shouldn't this be getChecked(props)?
131
var checked = props.checked;
132
if (checked != null) {
src/renderers/dom/client/wrappers/ReactDOMSelect.js
+18
@@ -19,6 +19,7 @@ var assign = require('Object.assign');
19
var warning = require('warning');
20
21
var didWarnValueLink = false;
22
+var didWarnValueNull = false;
23
24
function updateOptionsIfPendingUpdateAndMounted() {
25
if (this._rootNodeID && this._wrapperState.pendingUpdate) {
@@ -43,6 +44,19 @@ function getDeclarationErrorAddendum(owner) {
44
return '';
45
}
46
47
+function warnIfValueIsNull(props) {
48
+ if (props != null && props.value === null && !didWarnValueNull) {
49
+ warning(
50
+ false,
51
+ '`value` prop on `select` should not be null. ' +
52
+ 'Consider using the empty string to clear the component or' +
53
+ ' `undefined` for uncontrolled components.'
54
+ );
55
+
56
+ didWarnValueNull = true;
57
+ }
58
+}
59
+
60
var valuePropNames = ['value', 'defaultValue'];
61
62
/**
@@ -153,6 +167,7 @@ var ReactDOMSelect = {
167
mountWrapper: function(inst, props) {
168
if (__DEV__) {
169
checkSelectPropTypes(inst, props);
170
+ warnIfValueIsNull(props);
171
}
172
173
var value = LinkedValueUtils.getValue(props);
@@ -172,6 +187,9 @@ var ReactDOMSelect = {
187
188
postUpdateWrapper: function(inst) {
189
var props = inst._currentElement.props;
190
+ if (__DEV__) {
191
+ warnIfValueIsNull(props);
192
+ }
193
194
// After the initial mount, we control selected-ness manually so don't pass
195
// this value down
src/renderers/dom/client/wrappers/ReactDOMTextarea.js
+20
-1
@@ -20,6 +20,7 @@ var invariant = require('invariant');
20
var warning = require('warning');
21
22
var didWarnValueLink = false;
23
+var didWarnValueNull = false;
24
25
function forceUpdateIfMounted() {
26
if (this._rootNodeID) {
@@ -28,6 +29,19 @@ function forceUpdateIfMounted() {
29
}
30
}
31
32
+function warnIfValueIsNull(props) {
33
+ if (props != null && props.value === null && !didWarnValueNull) {
34
+ warning(
35
+ false,
36
+ '`value` prop on `textarea` should not be null. ' +
37
+ 'Consider using the empty string to clear the component or' +
38
+ ' `undefined` for uncontrolled components.'
39
+ );
40
+
41
+ didWarnValueNull = true;
42
+ }
43
+}
44
+
45
/**
46
* Implements a <textarea> native component that allows setting `value`, and
47
* `defaultValue`. This differs from the traditional DOM API because value is
@@ -76,6 +90,7 @@ var ReactDOMTextarea = {
90
);
91
didWarnValueLink = true;
92
}
93
+ warnIfValueIsNull(props);
94
}
95
96
var defaultValue = props.defaultValue;
@@ -107,7 +122,6 @@ var ReactDOMTextarea = {
122
defaultValue = '';
123
}
124
var value = LinkedValueUtils.getValue(props);
110
-
125
inst._wrapperState = {
126
// We save the initial value so that `ReactDOMComponent` doesn't update
127
// `textContent` (unnecessary since we update value).
@@ -120,6 +134,11 @@ var ReactDOMTextarea = {
134
135
updateWrapper: function(inst) {
136
var props = inst._currentElement.props;
137
+
138
+ if (__DEV__) {
139
+ warnIfValueIsNull(props);
140
+ }
141
+
142
var value = LinkedValueUtils.getValue(props);
143
if (value != null) {
144
// Cast `value` to a string to ensure the value is set correctly. While
src/renderers/dom/client/wrappers/__tests__/ReactDOMInput-test.js
+11
@@ -403,4 +403,15 @@ describe('ReactDOMInput', function() {
403
<input type="checkbox" checkedLink={link} valueLink={emptyFunction} />;
404
expect(() => ReactDOM.render(instance, node)).toThrow();
405
});
406
+
407
+ it('should throw warning message if value is null', function() {
408
+ ReactTestUtils.renderIntoDocument(<input type="text" value={null} />);
409
+ expect(console.error.argsForCall[0][0]).toContain(
410
+ '`value` prop on `input` should not be null. Consider using the empty string to clear the component or'
411
+ + ' `undefined` for uncontrolled components.'
412
+ );
413
+
414
+ ReactTestUtils.renderIntoDocument(<input type="text" value={null} />);
415
+ expect(console.error.argsForCall.length).toBe(1);
416
+ });
417
});
src/renderers/dom/client/wrappers/__tests__/ReactDOMSelect-test.js
+13
@@ -463,4 +463,17 @@ describe('ReactDOMSelect', function() {
463
expect(node.options[1].selected).toBe(false); // giraffe
464
expect(node.options[2].selected).toBe(false); // gorilla
465
});
466
+
467
+ it('should throw warning message if value is null', function() {
468
+ spyOn(console, 'error');
469
+
470
+ ReactTestUtils.renderIntoDocument(<select value={null}><option value="test"/></select>);
471
+ expect(console.error.argsForCall[0][0]).toContain(
472
+ '`value` prop on `select` should not be null. Consider using the empty string to clear the component or'
473
+ + ' `undefined` for uncontrolled components.'
474
+ );
475
+
476
+ ReactTestUtils.renderIntoDocument(<select value={null}><option value="test"/></select>);
477
+ expect(console.error.argsForCall.length).toBe(1);
478
+ });
479
});
src/renderers/dom/client/wrappers/__tests__/ReactDOMTextarea-test.js
+13
@@ -265,4 +265,17 @@ describe('ReactDOMTextarea', function() {
265
renderTextarea(<textarea />, container);
266
ReactDOM.unmountComponentAtNode(container);
267
});
268
+
269
+ it('should throw warning message if value is null', function() {
270
+ spyOn(console, 'error');
271
+
272
+ ReactTestUtils.renderIntoDocument(<textarea value={null} />);
273
+ expect(console.error.argsForCall[0][0]).toContain(
274
+ '`value` prop on `textarea` should not be null. Consider using the empty string to clear the component or'
275
+ + ' `undefined` for uncontrolled components.'
276
+ );
277
+
278
+ ReactTestUtils.renderIntoDocument(<textarea value={null} />);
279
+ expect(console.error.argsForCall.length).toBe(1);
280
+ });
281
});