@@ -25,6 +25,7 @@ var ReactBrowserComponentMixin = require('ReactBrowserComponentMixin');
2525var ReactCompositeComponent = require ( 'ReactCompositeComponent' ) ;
2626var ReactDOM = require ( 'ReactDOM' ) ;
2727var ReactMount = require ( 'ReactMount' ) ;
28+ var ReactUpdates = require ( 'ReactUpdates' ) ;
2829
2930var invariant = require ( 'invariant' ) ;
3031var merge = require ( 'merge' ) ;
@@ -34,6 +35,13 @@ var input = ReactDOM.input;
3435
3536var instancesByReactID = { } ;
3637
38+ function forceUpdateIfMounted ( ) {
39+ /*jshint validthis:true */
40+ if ( this . isMounted ( ) ) {
41+ this . forceUpdate ( ) ;
42+ }
43+ }
44+
3745/**
3846 * Implements an <input> native component that allows setting these optional
3947 * props: `checked`, `value`, `defaultChecked`, and `defaultValue`.
@@ -58,16 +66,11 @@ var ReactDOMInput = ReactCompositeComponent.createClass({
5866 getInitialState : function ( ) {
5967 var defaultValue = this . props . defaultValue ;
6068 return {
61- checked : this . props . defaultChecked || false ,
62- value : defaultValue != null ? defaultValue : null
69+ initialChecked : this . props . defaultChecked || false ,
70+ initialValue : defaultValue != null ? defaultValue : null
6371 } ;
6472 } ,
6573
66- shouldComponentUpdate : function ( ) {
67- // Defer any updates to this component during the `onChange` handler.
68- return ! this . _isChanging ;
69- } ,
70-
7174 render : function ( ) {
7275 // Clone `this.props` so we don't mutate the input.
7376 var props = merge ( this . props ) ;
@@ -76,10 +79,10 @@ var ReactDOMInput = ReactCompositeComponent.createClass({
7679 props . defaultValue = null ;
7780
7881 var value = LinkedValueUtils . getValue ( this ) ;
79- props . value = value != null ? value : this . state . value ;
82+ props . value = value != null ? value : this . state . initialValue ;
8083
8184 var checked = LinkedValueUtils . getChecked ( this ) ;
82- props . checked = checked != null ? checked : this . state . checked ;
85+ props . checked = checked != null ? checked : this . state . initialChecked ;
8386
8487 props . onChange = this . _handleChange ;
8588
@@ -119,14 +122,12 @@ var ReactDOMInput = ReactCompositeComponent.createClass({
119122 var returnValue ;
120123 var onChange = LinkedValueUtils . getOnChange ( this ) ;
121124 if ( onChange ) {
122- this . _isChanging = true ;
123125 returnValue = onChange . call ( this , event ) ;
124- this . _isChanging = false ;
125126 }
126- this . setState ( {
127- checked : event . target . checked ,
128- value : event . target . value
129- } ) ;
127+ // Here we use setImmediate to wait until all updates have propagated, which
128+ // is important when using controlled components within layers:
129+ // https://github.com/facebook/react/issues/1698
130+ ReactUpdates . setImmediate ( forceUpdateIfMounted , this ) ;
130131
131132 var name = this . props . name ;
132133 if ( this . props . type === 'radio' && name != null ) {
@@ -164,13 +165,10 @@ var ReactDOMInput = ReactCompositeComponent.createClass({
164165 'ReactDOMInput: Unknown radio button ID %s.' ,
165166 otherID
166167 ) ;
167- // In some cases, this will actually change the `checked` state value.
168- // In other cases, there's no change but this forces a reconcile upon
169- // which componentDidUpdate will reset the DOM property to whatever it
170- // should be.
171- otherInstance . setState ( {
172- checked : false
173- } ) ;
168+ // If this is a controlled radio button group, forcing the input that
169+ // was previously checked to update will cause it to be come re-checked
170+ // as appropriate.
171+ ReactUpdates . setImmediate ( forceUpdateIfMounted , otherInstance ) ;
174172 }
175173 }
176174
0 commit comments