Stringify value in ReactDOMInput / ChangeEventPlugin

This fixes two bugs related to string-casting in React:

 # Setting `<input value={0} />` would use an empty `value` because `0` is falsey.
 # Using `onChange` and `setState` with non-strings could lead to an infinite loop.

The latter is possible with controlled inputs when:

 - User changes input value.
 - `onpropertychange` fires.
 - `ChangeEventPlugin` dispatches `onChange`.
 - A handler responds via `this.setState` with a non-string value (e.g. a number).
 - The input re-renders and re-sets `value`.
 - The new `value` is not a string, but the current `value` (read from the element) is cast to a string automatically by the browser.
 - This triggers another `onpropertychange`.
 - `ChangeEventPlugin` dispatches another `onChange`.
 - ...
This commit is contained in:
Tim Yung
2013-07-12 15:40:55 -07:00
committed by Paul O’Shannessy
parent cf83fbe397
commit eee3980749
2 changed files with 8 additions and 4 deletions
+5 -2
View File
@@ -62,7 +62,8 @@ var ReactDOMInput = ReactCompositeComponent.createClass({
},
getValue: function() {
return this.props.value != null ? this.props.value : this.state.value;
// Cast `this.props.value` to a string so equality checks pass.
return this.props.value != null ? '' + this.props.value : this.state.value;
},
render: function() {
@@ -85,10 +86,12 @@ var ReactDOMInput = ReactCompositeComponent.createClass({
);
}
if (this.props.value != null) {
// Cast `this.props.value` to a string so falsey values that cast to
// truthy strings are not ignored.
DOMPropertyOperations.setValueForProperty(
rootNode,
'value',
this.props.value || ''
'' + this.props.value || ''
);
}
},
+3 -2
View File
@@ -169,7 +169,8 @@ var newValueProp = {
return activeElementValueProp.get.call(this);
},
set: function(val) {
activeElementValue = val;
// Cast to a string so we can do equality checks.
activeElementValue = '' + val;
activeElementValueProp.set.call(this, val);
}
};
@@ -231,7 +232,7 @@ function handlePropertyChange(nativeEvent) {
/**
* If a `change` event should be fired, returns the target's ID.
*/
function getTargetIDForInputEvent(
function getTargetIDForInputEvent(
topLevelType,
topLevelTarget,
topLevelTargetID) {