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.
Nathan Hunzaker committed
Jul 22, 2016 at 21:38 UTC
08a0895887c82e379d7717439c7a8d0b015e0696
2 files changed
+36
-6
src/renderers/dom/client/wrappers/__tests__/ReactDOMInput-test.js
+21
@@ -769,4 +769,25 @@ describe('ReactDOMInput', function() {
769
);
770
expect(input.value).toBe('hi');
771
});
772
+
773
+ it('does not raise a validation warning when it switches types', function() {
774
+ var Input = React.createClass({
775
+ getInitialState() {
776
+ return { type: 'number', value: 1000 };
777
+ },
778
+ render() {
779
+ var { value, type } = this.state;
780
+ return (<input onChange={() => {}} type={type} value={value} />);
781
+ },
782
+ });
783
+
784
+ var input = ReactTestUtils.renderIntoDocument(<Input />);
785
+ var node = ReactDOM.findDOMNode(input);
786
+
787
+ // If the value is set before the type, a validation warning will raise and
788
+ // the value will not be assigned.
789
+ input.setState({ type: 'text', value: 'Test' });
790
+ expect(node.value).toEqual('Test');
791
+ });
792
+
793
});
src/renderers/dom/shared/ReactDOMComponent.js
+15
-6
@@ -907,7 +907,6 @@ ReactDOMComponent.Mixin = {
907
nextProps = ReactDOMButton.getHostProps(this, nextProps);
908
break;
909
case 'input':
910
- ReactDOMInput.updateWrapper(this);
910
lastProps = ReactDOMInput.getHostProps(this, lastProps);
911
nextProps = ReactDOMInput.getHostProps(this, nextProps);
912
break;
@@ -920,7 +919,6 @@ ReactDOMComponent.Mixin = {
919
nextProps = ReactDOMSelect.getHostProps(this, nextProps);
920
break;
921
case 'textarea':
923
- ReactDOMTextarea.updateWrapper(this);
922
lastProps = ReactDOMTextarea.getHostProps(this, lastProps);
923
nextProps = ReactDOMTextarea.getHostProps(this, nextProps);
924
break;
@@ -935,10 +933,21 @@ ReactDOMComponent.Mixin = {
933
context
934
);
935
938
- if (this._tag === 'select') {
939
- // <select> value update needs to occur after <option> children
940
- // reconciliation
941
- transaction.getReactMountReady().enqueue(postUpdateSelectWrapper, this);
936
+ switch (this._tag) {
937
+ case 'input':
938
+ // Update the wrapper around inputs *after* updating props. This has to
939
+ // happen after `_updateDOMProperties`. Otherwise HTML5 input validations
940
+ // raise warnings and prevent the new value from being assigned.
941
+ ReactDOMInput.updateWrapper(this);
942
+ break;
943
+ case 'textarea':
944
+ ReactDOMTextarea.updateWrapper(this);
945
+ break;
946
+ case 'select':
947
+ // <select> value update needs to occur after <option> children
948
+ // reconciliation
949
+ transaction.getReactMountReady().enqueue(postUpdateSelectWrapper, this);
950
+ break;
951
}
952
953
if (__DEV__) {