77 * @flow
88 */
99
10+ import type { InputWithWrapperState } from './ReactDOMInput' ;
11+
1012import {
1113 registrationNameDependencies ,
1214 possibleRegistrationNames ,
@@ -15,7 +17,6 @@ import {
1517import { canUseDOM } from 'shared/ExecutionEnvironment' ;
1618import { checkHtmlStringCoercion } from 'shared/CheckStringCoercion' ;
1719import { checkAttributeStringCoercion } from 'shared/CheckStringCoercion' ;
18- import { checkControlledValueProps } from '../shared/ReactControlledValuePropTypes' ;
1920
2021import {
2122 getValueForAttribute ,
@@ -26,24 +27,27 @@ import {
2627 setValueForNamespacedAttribute ,
2728} from './DOMPropertyOperations' ;
2829import {
29- validateInputProps ,
30- initInput ,
31- updateInputChecked ,
32- updateInput ,
33- restoreControlledInputState ,
30+ initWrapperState as ReactDOMInputInitWrapperState ,
31+ postMountWrapper as ReactDOMInputPostMountWrapper ,
32+ updateChecked as ReactDOMInputUpdateChecked ,
33+ updateWrapper as ReactDOMInputUpdateWrapper ,
34+ restoreControlledState as ReactDOMInputRestoreControlledState ,
3435} from './ReactDOMInput' ;
35- import { initOption , validateOptionProps } from './ReactDOMOption' ;
3636import {
37- validateSelectProps ,
38- initSelect ,
39- restoreControlledSelectState ,
40- updateSelect ,
37+ postMountWrapper as ReactDOMOptionPostMountWrapper ,
38+ validateProps as ReactDOMOptionValidateProps ,
39+ } from './ReactDOMOption' ;
40+ import {
41+ initWrapperState as ReactDOMSelectInitWrapperState ,
42+ postMountWrapper as ReactDOMSelectPostMountWrapper ,
43+ restoreControlledState as ReactDOMSelectRestoreControlledState ,
44+ postUpdateWrapper as ReactDOMSelectPostUpdateWrapper ,
4145} from './ReactDOMSelect' ;
4246import {
43- validateTextareaProps ,
44- initTextarea ,
45- updateTextarea ,
46- restoreControlledTextareaState ,
47+ initWrapperState as ReactDOMTextareaInitWrapperState ,
48+ postMountWrapper as ReactDOMTextareaPostMountWrapper ,
49+ updateWrapper as ReactDOMTextareaUpdateWrapper ,
50+ restoreControlledState as ReactDOMTextareaRestoreControlledState ,
4751} from './ReactDOMTextarea' ;
4852import { track } from './inputValueTracking' ;
4953import setInnerHTML from './setInnerHTML' ;
@@ -75,8 +79,6 @@ import {
7579 listenToNonDelegatedEvent ,
7680} from '../events/DOMPluginEventSystem' ;
7781
78- let didWarnControlledToUncontrolled = false ;
79- let didWarnUncontrolledToControlled = false ;
8082let didWarnInvalidHydration = false ;
8183let canDiffStyleForHydrationWarning ;
8284if ( __DEV__ ) {
@@ -803,9 +805,7 @@ export function setInitialProperties(
803805 break ;
804806 }
805807 case 'input' : {
806- if ( __DEV__ ) {
807- checkControlledValueProps ( 'input' , props ) ;
808- }
808+ ReactDOMInputInitWrapperState ( domElement , props ) ;
809809 // We listen to this event in case to ensure emulated bubble
810810 // listeners still fire for the invalid event.
811811 listenToNonDelegatedEvent ( 'invalid' , domElement ) ;
@@ -834,10 +834,10 @@ export function setInitialProperties(
834834 break ;
835835 }
836836 case 'checked' : {
837+ const node = ( ( domElement : any ) : InputWithWrapperState ) ;
837838 const checked =
838- propValue != null ? propValue : props . defaultChecked ;
839- const inputElement : HTMLInputElement = ( domElement : any ) ;
840- inputElement . checked =
839+ propValue != null ? propValue : node . _wrapperState . initialChecked ;
840+ node . checked =
841841 ! ! checked &&
842842 typeof checked !== 'function' &&
843843 checked !== 'symbol' ;
@@ -866,14 +866,11 @@ export function setInitialProperties(
866866 // TODO: Make sure we check if this is still unmounted or do any clean
867867 // up necessary since we never stop tracking anymore.
868868 track ( ( domElement : any ) ) ;
869- validateInputProps ( domElement , props ) ;
870- initInput ( domElement , props , false ) ;
869+ ReactDOMInputPostMountWrapper ( domElement , props , false ) ;
871870 return ;
872871 }
873872 case 'select' : {
874- if ( __DEV__ ) {
875- checkControlledValueProps ( 'select' , props ) ;
876- }
873+ ReactDOMSelectInitWrapperState ( domElement , props ) ;
877874 // We listen to this event in case to ensure emulated bubble
878875 // listeners still fire for the invalid event.
879876 listenToNonDelegatedEvent ( 'invalid' , domElement ) ;
@@ -896,14 +893,11 @@ export function setInitialProperties(
896893 }
897894 }
898895 }
899- validateSelectProps ( domElement , props ) ;
900- initSelect ( domElement , props ) ;
896+ ReactDOMSelectPostMountWrapper ( domElement , props ) ;
901897 return ;
902898 }
903899 case 'textarea' : {
904- if ( __DEV__ ) {
905- checkControlledValueProps ( 'textarea' , props ) ;
906- }
900+ ReactDOMTextareaInitWrapperState ( domElement , props ) ;
907901 // We listen to this event in case to ensure emulated bubble
908902 // listeners still fire for the invalid event.
909903 listenToNonDelegatedEvent ( 'invalid' , domElement ) ;
@@ -942,12 +936,11 @@ export function setInitialProperties(
942936 // TODO: Make sure we check if this is still unmounted or do any clean
943937 // up necessary since we never stop tracking anymore.
944938 track ( ( domElement : any ) ) ;
945- validateTextareaProps ( domElement , props ) ;
946- initTextarea ( domElement , props ) ;
939+ ReactDOMTextareaPostMountWrapper ( domElement , props ) ;
947940 return ;
948941 }
949942 case 'option' : {
950- validateOptionProps ( domElement , props ) ;
943+ ReactDOMOptionValidateProps ( domElement , props ) ;
951944 for ( const propKey in props ) {
952945 if ( ! props . hasOwnProperty ( propKey ) ) {
953946 continue ;
@@ -970,7 +963,7 @@ export function setInitialProperties(
970963 }
971964 }
972965 }
973- initOption ( domElement , props ) ;
966+ ReactDOMOptionPostMountWrapper ( domElement , props ) ;
974967 return ;
975968 }
976969 case 'dialog' : {
@@ -1220,17 +1213,17 @@ export function updateProperties(
12201213 // In the middle of an update, it is possible to have multiple checked.
12211214 // When a checked radio tries to change name, browser makes another radio's checked false.
12221215 if ( nextProps . type === 'radio' && nextProps . name != null ) {
1223- updateInputChecked ( domElement , nextProps ) ;
1216+ ReactDOMInputUpdateChecked ( domElement , nextProps ) ;
12241217 }
12251218 for ( let i = 0 ; i < updatePayload . length ; i += 2 ) {
12261219 const propKey = updatePayload [ i ] ;
12271220 const propValue = updatePayload [ i + 1 ] ;
12281221 switch ( propKey ) {
12291222 case 'checked' : {
1223+ const node = ( ( domElement : any ) : InputWithWrapperState ) ;
12301224 const checked =
1231- propValue != null ? propValue : nextProps . defaultChecked ;
1232- const inputElement : HTMLInputElement = ( domElement : any ) ;
1233- inputElement . checked =
1225+ propValue != null ? propValue : node . _wrapperState . initialChecked ;
1226+ node . checked =
12341227 ! ! checked &&
12351228 typeof checked !== 'function' &&
12361229 checked !== 'symbol' ;
@@ -1256,50 +1249,10 @@ export function updateProperties(
12561249 }
12571250 }
12581251 }
1259-
1260- if ( __DEV__ ) {
1261- const wasControlled =
1262- lastProps . type === 'checkbox' || lastProps . type === 'radio'
1263- ? lastProps . checked != null
1264- : lastProps . value != null ;
1265- const isControlled =
1266- nextProps . type === 'checkbox' || nextProps . type === 'radio'
1267- ? nextProps . checked != null
1268- : nextProps . value != null ;
1269-
1270- if (
1271- ! wasControlled &&
1272- isControlled &&
1273- ! didWarnUncontrolledToControlled
1274- ) {
1275- console . error (
1276- 'A component is changing an uncontrolled input to be controlled. ' +
1277- 'This is likely caused by the value changing from undefined to ' +
1278- 'a defined value, which should not happen. ' +
1279- 'Decide between using a controlled or uncontrolled input ' +
1280- 'element for the lifetime of the component. More info: https://reactjs.org/link/controlled-components' ,
1281- ) ;
1282- didWarnUncontrolledToControlled = true ;
1283- }
1284- if (
1285- wasControlled &&
1286- ! isControlled &&
1287- ! didWarnControlledToUncontrolled
1288- ) {
1289- console . error (
1290- 'A component is changing a controlled input to be uncontrolled. ' +
1291- 'This is likely caused by the value changing from a defined to ' +
1292- 'undefined, which should not happen. ' +
1293- 'Decide between using a controlled or uncontrolled input ' +
1294- 'element for the lifetime of the component. More info: https://reactjs.org/link/controlled-components' ,
1295- ) ;
1296- didWarnControlledToUncontrolled = true ;
1297- }
1298- }
12991252 // Update the wrapper around inputs *after* updating props. This has to
13001253 // happen after updating the rest of props. Otherwise HTML5 input validations
13011254 // raise warnings and prevent the new value from being assigned.
1302- updateInput ( domElement , nextProps ) ;
1255+ ReactDOMInputUpdateWrapper ( domElement , nextProps ) ;
13031256 return ;
13041257 }
13051258 case 'select' : {
@@ -1319,7 +1272,7 @@ export function updateProperties(
13191272 }
13201273 // <select> value update needs to occur after <option> children
13211274 // reconciliation
1322- updateSelect ( domElement , lastProps , nextProps ) ;
1275+ ReactDOMSelectPostUpdateWrapper ( domElement , nextProps ) ;
13231276 return ;
13241277 }
13251278 case 'textarea' : {
@@ -1350,7 +1303,7 @@ export function updateProperties(
13501303 }
13511304 }
13521305 }
1353- updateTextarea ( domElement , nextProps ) ;
1306+ ReactDOMTextareaUpdateWrapper ( domElement , nextProps ) ;
13541307 return ;
13551308 }
13561309 case 'option' : {
@@ -2310,47 +2263,38 @@ export function diffHydratedProperties(
23102263 listenToNonDelegatedEvent ( 'toggle' , domElement ) ;
23112264 break ;
23122265 case 'input' :
2313- if ( __DEV__ ) {
2314- checkControlledValueProps ( 'input' , props ) ;
2315- }
2266+ ReactDOMInputInitWrapperState ( domElement , props ) ;
23162267 // We listen to this event in case to ensure emulated bubble
23172268 // listeners still fire for the invalid event.
23182269 listenToNonDelegatedEvent ( 'invalid' , domElement ) ;
23192270 // TODO: Make sure we check if this is still unmounted or do any clean
23202271 // up necessary since we never stop tracking anymore.
23212272 track ( ( domElement : any ) ) ;
2322- validateInputProps ( domElement , props ) ;
23232273 // For input and textarea we current always set the value property at
23242274 // post mount to force it to diverge from attributes. However, for
23252275 // option and select we don't quite do the same thing and select
23262276 // is not resilient to the DOM state changing so we don't do that here.
23272277 // TODO: Consider not doing this for input and textarea.
2328- initInput ( domElement , props , true ) ;
2278+ ReactDOMInputPostMountWrapper ( domElement , props , true ) ;
23292279 break ;
23302280 case 'option' :
2331- validateOptionProps ( domElement , props ) ;
2281+ ReactDOMOptionValidateProps ( domElement , props ) ;
23322282 break ;
23332283 case 'select' :
2334- if ( __DEV__ ) {
2335- checkControlledValueProps ( 'select' , props ) ;
2336- }
2284+ ReactDOMSelectInitWrapperState ( domElement , props ) ;
23372285 // We listen to this event in case to ensure emulated bubble
23382286 // listeners still fire for the invalid event.
23392287 listenToNonDelegatedEvent ( 'invalid' , domElement ) ;
2340- validateSelectProps ( domElement , props ) ;
23412288 break ;
23422289 case 'textarea' :
2343- if ( __DEV__ ) {
2344- checkControlledValueProps ( 'textarea' , props ) ;
2345- }
2290+ ReactDOMTextareaInitWrapperState ( domElement , props ) ;
23462291 // We listen to this event in case to ensure emulated bubble
23472292 // listeners still fire for the invalid event.
23482293 listenToNonDelegatedEvent ( 'invalid' , domElement ) ;
23492294 // TODO: Make sure we check if this is still unmounted or do any clean
23502295 // up necessary since we never stop tracking anymore.
23512296 track ( ( domElement : any ) ) ;
2352- validateTextareaProps ( domElement , props ) ;
2353- initTextarea ( domElement , props ) ;
2297+ ReactDOMTextareaPostMountWrapper ( domElement , props ) ;
23542298 break ;
23552299 }
23562300
@@ -2528,13 +2472,13 @@ export function restoreControlledState(
25282472) : void {
25292473 switch ( tag ) {
25302474 case 'input ':
2531- restoreControlledInputState ( domElement , props ) ;
2475+ ReactDOMInputRestoreControlledState ( domElement , props ) ;
25322476 return ;
25332477 case 'textarea ':
2534- restoreControlledTextareaState ( domElement , props ) ;
2478+ ReactDOMTextareaRestoreControlledState ( domElement , props ) ;
25352479 return ;
25362480 case 'select ':
2537- restoreControlledSelectState ( domElement , props ) ;
2481+ ReactDOMSelectRestoreControlledState ( domElement , props ) ;
25382482 return ;
25392483 }
25402484}
0 commit comments