Skip to content

Commit 77d6143

Browse files
nhunzakerzpao
authored andcommitted
Avoid validation warning when inputs change type (#7333)
For controlled inputs, `updateWrapper` was getting called before the `type` prop had a chance to update. This could lead to a case where switching from the `text` to `number` type caused a validation error that would prevent the proper input value from being assigned. This commit moves the call to `ReactDOMInput.updateWrapper` below `_updateProperties` to avoid this situation. (cherry picked from commit 08a0895)
1 parent d0fc12d commit 77d6143

File tree

2 files changed

+36
-6
lines changed

2 files changed

+36
-6
lines changed

src/renderers/dom/client/wrappers/__tests__/ReactDOMInput-test.js

+21
Original file line numberDiff line numberDiff line change
@@ -760,4 +760,25 @@ describe('ReactDOMInput', function() {
760760
);
761761
expect(input.value).toBe('hi');
762762
});
763+
764+
it('does not raise a validation warning when it switches types', function() {
765+
var Input = React.createClass({
766+
getInitialState() {
767+
return { type: 'number', value: 1000 };
768+
},
769+
render() {
770+
var { value, type } = this.state;
771+
return (<input onChange={() => {}} type={type} value={value} />);
772+
},
773+
});
774+
775+
var input = ReactTestUtils.renderIntoDocument(<Input />);
776+
var node = ReactDOM.findDOMNode(input);
777+
778+
// If the value is set before the type, a validation warning will raise and
779+
// the value will not be assigned.
780+
input.setState({ type: 'text', value: 'Test' });
781+
expect(node.value).toEqual('Test');
782+
});
783+
763784
});

src/renderers/dom/shared/ReactDOMComponent.js

+15-6
Original file line numberDiff line numberDiff line change
@@ -900,7 +900,6 @@ ReactDOMComponent.Mixin = {
900900
nextProps = ReactDOMButton.getHostProps(this, nextProps);
901901
break;
902902
case 'input':
903-
ReactDOMInput.updateWrapper(this);
904903
lastProps = ReactDOMInput.getHostProps(this, lastProps);
905904
nextProps = ReactDOMInput.getHostProps(this, nextProps);
906905
break;
@@ -913,7 +912,6 @@ ReactDOMComponent.Mixin = {
913912
nextProps = ReactDOMSelect.getHostProps(this, nextProps);
914913
break;
915914
case 'textarea':
916-
ReactDOMTextarea.updateWrapper(this);
917915
lastProps = ReactDOMTextarea.getHostProps(this, lastProps);
918916
nextProps = ReactDOMTextarea.getHostProps(this, nextProps);
919917
break;
@@ -928,10 +926,21 @@ ReactDOMComponent.Mixin = {
928926
context
929927
);
930928

931-
if (this._tag === 'select') {
932-
// <select> value update needs to occur after <option> children
933-
// reconciliation
934-
transaction.getReactMountReady().enqueue(postUpdateSelectWrapper, this);
929+
switch (this._tag) {
930+
case 'input':
931+
// Update the wrapper around inputs *after* updating props. This has to
932+
// happen after `_updateDOMProperties`. Otherwise HTML5 input validations
933+
// raise warnings and prevent the new value from being assigned.
934+
ReactDOMInput.updateWrapper(this);
935+
break;
936+
case 'textarea':
937+
ReactDOMTextarea.updateWrapper(this);
938+
break;
939+
case 'select':
940+
// <select> value update needs to occur after <option> children
941+
// reconciliation
942+
transaction.getReactMountReady().enqueue(postUpdateSelectWrapper, this);
943+
break;
935944
}
936945

937946
if (__DEV__) {

0 commit comments

Comments
 (0)