@@ -57,30 +57,14 @@ function isControlled(props) {
5757
5858export function getHostProps ( element : Element , props : Object ) {
5959 var node = ( ( element : any ) : InputWithWrapperState ) ;
60- var value = props . value ;
6160 var checked = props . checked ;
6261
63- var hostProps = Object . assign (
64- {
65- // Make sure we set .type before any other properties (setting .value
66- // before .type means .value is lost in IE11 and below)
67- type : undefined ,
68- // Make sure we set .step before .value (setting .value before .step
69- // means .value is rounded on mount, based upon step precision)
70- step : undefined ,
71- // Make sure we set .min & .max before .value (to ensure proper order
72- // in corner cases such as min or max deriving from value, e.g. Issue #7170)
73- min : undefined ,
74- max : undefined ,
75- } ,
76- props ,
77- {
78- defaultChecked : undefined ,
79- defaultValue : undefined ,
80- value : value != null ? value : node . _wrapperState . initialValue ,
81- checked : checked != null ? checked : node . _wrapperState . initialChecked ,
82- } ,
83- ) ;
62+ var hostProps = Object . assign ( { } , props , {
63+ defaultChecked : undefined ,
64+ defaultValue : undefined ,
65+ value : undefined ,
66+ checked : checked != null ? checked : node . _wrapperState . initialChecked ,
67+ } ) ;
8468
8569 return hostProps ;
8670}
@@ -131,7 +115,7 @@ export function initWrapperState(element: Element, props: Object) {
131115 }
132116 }
133117
134- var defaultValue = props . defaultValue ;
118+ var defaultValue = props . defaultValue == null ? '' : props . defaultValue ;
135119 var node = ( ( element : any ) : InputWithWrapperState ) ;
136120 node . _wrapperState = {
137121 initialChecked :
@@ -190,6 +174,7 @@ export function updateWrapper(element: Element, props: Object) {
190174 }
191175
192176 var value = props . value ;
177+ var valueAsString = '' + props . value ;
193178 if ( value != null ) {
194179 if ( value === 0 && node . value === '' ) {
195180 node . value = '0' ;
@@ -206,26 +191,17 @@ export function updateWrapper(element: Element, props: Object) {
206191 ) {
207192 // Cast `value` to a string to ensure the value is set correctly. While
208193 // browsers typically do this as necessary, jsdom doesn't.
209- node . value = '' + value ;
194+ node . value = valueAsString ;
210195 }
211- } else if ( node . value !== '' + value ) {
196+ } else if ( node . value !== valueAsString ) {
212197 // Cast `value` to a string to ensure the value is set correctly. While
213198 // browsers typically do this as necessary, jsdom doesn't.
214- node . value = '' + value ;
199+ node . value = valueAsString ;
215200 }
201+ synchronizeDefaultValue ( node , props . type , valueAsString ) ;
216202 } else {
217203 if ( props . value == null && props . defaultValue != null ) {
218- // In Chrome, assigning defaultValue to certain input types triggers input validation.
219- // For number inputs, the display value loses trailing decimal points. For email inputs,
220- // Chrome raises "The specified value <x> is not a valid email address".
221- //
222- // Here we check to see if the defaultValue has actually changed, avoiding these problems
223- // when the user is inputting text
224- //
225- // https://github.com/facebook/react/issues/7253
226- if ( node . defaultValue !== '' + props . defaultValue ) {
227- node . defaultValue = '' + props . defaultValue ;
228- }
204+ synchronizeDefaultValue ( node , props . type , '' + props . defaultValue ) ;
229205 }
230206 if ( props . checked == null && props . defaultChecked != null ) {
231207 node . defaultChecked = ! ! props . defaultChecked ;
@@ -235,32 +211,20 @@ export function updateWrapper(element: Element, props: Object) {
235211
236212export function postMountWrapper ( element : Element , props : Object ) {
237213 var node = ( ( element : any ) : InputWithWrapperState ) ;
214+ var hasUserInput = node . value !== '' ;
215+ var value = node . _wrapperState . initialValue ;
238216
239- // Detach value from defaultValue. We won't do anything if we're working on
240- // submit or reset inputs as those values & defaultValues are linked. They
241- // are not resetable nodes so this operation doesn't matter and actually
242- // removes browser-default values (eg "Submit Query") when no value is
243- // provided.
217+ if ( value !== '' || props . hasOwnProperty ( 'value' ) ) {
218+ // Do not assign value if it is already set. This prevents user text input
219+ // from being lost during SSR hydration.
220+ if ( ! hasUserInput ) {
221+ node . value = value ;
222+ }
244223
245- switch ( props . type ) {
246- case 'submit' :
247- case 'reset' :
248- break ;
249- case 'color' :
250- case 'date' :
251- case 'datetime' :
252- case 'datetime-local' :
253- case 'month' :
254- case 'time' :
255- case 'week' :
256- // This fixes the no-show issue on iOS Safari and Android Chrome:
257- // https://github.com/facebook/react/issues/7233
258- node . value = '' ;
259- node . value = node . defaultValue ;
260- break ;
261- default :
262- node . value = node . value ;
263- break ;
224+ // value must be assigned before defaultValue. This fixes an issue where the
225+ // visually displayed value of date inputs disappears on mobile Safari and Chrome:
226+ // https://github.com/facebook/react/issues/7233
227+ node . defaultValue = value ;
264228 }
265229
266230 // Normally, we'd just do `node.checked = node.checked` upon initial mount, less this bug
@@ -327,3 +291,21 @@ function updateNamedCousins(rootNode, props) {
327291 }
328292 }
329293}
294+
295+ // In Chrome, assigning defaultValue to certain input types triggers input validation.
296+ // For number inputs, the display value loses trailing decimal points. For email inputs,
297+ // Chrome raises "The specified value <x> is not a valid email address".
298+ //
299+ // Here we check to see if the defaultValue has actually changed, avoiding these problems
300+ // when the user is inputting text
301+ //
302+ // https://github.com/facebook/react/issues/7253
303+ function synchronizeDefaultValue ( node : Element , type : ?string , value : string ) {
304+ if (
305+ // Focused number inputs synchronize on blur. See ChangeEventPlugin.js
306+ ( type !== 'number' || node . ownerDocument . activeElement !== node ) &&
307+ node . defaultValue !== value
308+ ) {
309+ node . defaultValue = value ;
310+ }
311+ }
0 commit comments