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

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