@samitouri / QOS-React / commits / 08a0895887

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__) {