@@ -22,11 +22,14 @@ var assign = require('Object.assign');
22
22
23
23
var select = ReactElement . createFactory ( 'select' ) ;
24
24
25
- function updateWithPendingValueIfMounted ( ) {
25
+ function updateOptionsIfPendingUpdateAndMounted ( ) {
26
26
/*jshint validthis:true */
27
- if ( this . isMounted ( ) ) {
28
- this . setState ( { value : this . _pendingValue } ) ;
29
- this . _pendingValue = 0 ;
27
+ if ( this . _pendingUpdate ) {
28
+ this . _pendingUpdate = false ;
29
+ var value = LinkedValueUtils . getValue ( this ) ;
30
+ if ( value != null && this . isMounted ( ) ) {
31
+ updateOptions ( this , value ) ;
32
+ }
30
33
}
31
34
}
32
35
@@ -56,40 +59,43 @@ function selectValueType(props, propName, componentName) {
56
59
}
57
60
58
61
/**
59
- * If `value` is supplied, updates <option> elements on mount and update.
60
62
* @param {ReactComponent } component Instance of ReactDOMSelect
61
- * @param {?* } propValue For uncontrolled components, null/undefined. For
62
- * controlled components, a string (or with `multiple`, a list of strings).
63
+ * @param {* } propValue A stringable (with `multiple`, a list of stringables).
63
64
* @private
64
65
*/
65
66
function updateOptions ( component , propValue ) {
66
- var multiple = component . props . multiple ;
67
- var value = propValue != null ? propValue : component . state . value ;
68
- var options = component . getDOMNode ( ) . options ;
69
67
var selectedValue , i , l ;
70
- if ( multiple ) {
68
+ var options = component . getDOMNode ( ) . options ;
69
+
70
+ if ( component . props . multiple ) {
71
71
selectedValue = { } ;
72
- for ( i = 0 , l = value . length ; i < l ; ++ i ) {
73
- selectedValue [ '' + value [ i ] ] = true ;
72
+ for ( i = 0 , l = propValue . length ; i < l ; i ++ ) {
73
+ selectedValue [ '' + propValue [ i ] ] = true ;
74
+ }
75
+ for ( i = 0 , l = options . length ; i < l ; i ++ ) {
76
+ var selected = selectedValue . hasOwnProperty ( options [ i ] . value ) ;
77
+ if ( options [ i ] . selected !== selected ) {
78
+ options [ i ] . selected = selected ;
79
+ }
74
80
}
75
81
} else {
76
- selectedValue = '' + value ;
77
- }
78
- for ( i = 0 , l = options . length ; i < l ; i ++ ) {
79
- var selected = multiple ?
80
- selectedValue . hasOwnProperty ( options [ i ] . value ) :
81
- options [ i ] . value === selectedValue ;
82
-
83
- if ( selected !== options [ i ] . selected ) {
84
- options [ i ] . selected = selected ;
82
+ // Do not set `select.value` as exact behavior isn't consistent across all
83
+ // browsers for all cases.
84
+ selectedValue = '' + propValue ;
85
+ for ( i = 0 , l = options . length ; i < l ; i ++ ) {
86
+ if ( options [ i ] . value === selectedValue ) {
87
+ options [ i ] . selected = true ;
88
+ return ;
89
+ }
85
90
}
91
+ options [ 0 ] . selected = true ;
86
92
}
87
93
}
88
94
89
95
/**
90
96
* Implements a <select> native component that allows optionally setting the
91
97
* props `value` and `defaultValue`. If `multiple` is false, the prop must be a
92
- * string . If `multiple` is true, the prop must be an array of strings .
98
+ * stringable . If `multiple` is true, the prop must be an array of stringables .
93
99
*
94
100
* If `value` is not supplied (or null/undefined), user actions that change the
95
101
* selected option will trigger updates to the rendered options.
@@ -111,22 +117,6 @@ var ReactDOMSelect = ReactClass.createClass({
111
117
value : selectValueType
112
118
} ,
113
119
114
- getInitialState : function ( ) {
115
- return { value : this . props . defaultValue || ( this . props . multiple ? [ ] : '' ) } ;
116
- } ,
117
-
118
- componentWillMount : function ( ) {
119
- this . _pendingValue = null ;
120
- } ,
121
-
122
- componentWillReceiveProps : function ( nextProps ) {
123
- if ( ! this . props . multiple && nextProps . multiple ) {
124
- this . setState ( { value : [ this . state . value ] } ) ;
125
- } else if ( this . props . multiple && ! nextProps . multiple ) {
126
- this . setState ( { value : this . state . value [ 0 ] } ) ;
127
- }
128
- } ,
129
-
130
120
render : function ( ) {
131
121
// Clone `this.props` so we don't mutate the input.
132
122
var props = assign ( { } , this . props ) ;
@@ -137,16 +127,32 @@ var ReactDOMSelect = ReactClass.createClass({
137
127
return select ( props , this . props . children ) ;
138
128
} ,
139
129
130
+ componentWillMount : function ( ) {
131
+ this . _pendingUpdate = false ;
132
+ } ,
133
+
140
134
componentDidMount : function ( ) {
141
- updateOptions ( this , LinkedValueUtils . getValue ( this ) ) ;
135
+ var value = LinkedValueUtils . getValue ( this ) ;
136
+ if ( value != null ) {
137
+ updateOptions ( this , value ) ;
138
+ } else if ( this . props . defaultValue != null ) {
139
+ updateOptions ( this , this . props . defaultValue ) ;
140
+ }
142
141
} ,
143
142
144
143
componentDidUpdate : function ( prevProps ) {
145
144
var value = LinkedValueUtils . getValue ( this ) ;
146
- var prevMultiple = ! ! prevProps . multiple ;
147
- var multiple = ! ! this . props . multiple ;
148
- if ( value != null || prevMultiple !== multiple ) {
145
+ if ( value != null ) {
146
+ this . _pendingUpdate = false ;
149
147
updateOptions ( this , value ) ;
148
+ } else if ( ! prevProps . multiple !== ! this . props . multiple ) {
149
+ // For simplicity, reapply `defaultValue` if `multiple` is toggled.
150
+ if ( this . props . defaultValue != null ) {
151
+ updateOptions ( this , this . props . defaultValue ) ;
152
+ } else {
153
+ // Revert the select back to its default unselected state.
154
+ updateOptions ( this , this . props . multiple ? [ ] : '' ) ;
155
+ }
150
156
}
151
157
} ,
152
158
@@ -157,21 +163,8 @@ var ReactDOMSelect = ReactClass.createClass({
157
163
returnValue = onChange . call ( this , event ) ;
158
164
}
159
165
160
- var selectedValue ;
161
- if ( this . props . multiple ) {
162
- selectedValue = [ ] ;
163
- var options = event . target . options ;
164
- for ( var i = 0 , l = options . length ; i < l ; i ++ ) {
165
- if ( options [ i ] . selected ) {
166
- selectedValue . push ( options [ i ] . value ) ;
167
- }
168
- }
169
- } else {
170
- selectedValue = event . target . value ;
171
- }
172
-
173
- this . _pendingValue = selectedValue ;
174
- ReactUpdates . asap ( updateWithPendingValueIfMounted , this ) ;
166
+ this . _pendingUpdate = true ;
167
+ ReactUpdates . asap ( updateOptionsIfPendingUpdateAndMounted , this ) ;
175
168
return returnValue ;
176
169
}
177
170
0 commit comments