99
1010import type { Fiber } from './ReactFiber' ;
1111import type { ExpirationTime } from './ReactFiberExpirationTime' ;
12+ import type { CapturedValue } from './ReactCapturedValue' ;
1213
1314import { Update } from 'shared/ReactTypeOfSideEffect' ;
1415import {
16+ enableGetDerivedStateFromCatch ,
1517 debugRenderPhaseSideEffects ,
1618 debugRenderPhaseSideEffectsForStrictMode ,
1719 warnAboutDeprecatedLifecycles ,
@@ -94,17 +96,17 @@ if (__DEV__) {
9496 } ) ;
9597 Object . freeze ( fakeInternalInstance ) ;
9698}
97-
98- export function callGetDerivedStateFromCatch (
99- ctor : any ,
100- capturedValues : Array < mixed > ,
101- ) {
102- // TODO:
103- // for (let i = 0; i < capturedValues.length; i++ ) {
104- // const capturedValue: CapturedValue<mixed> = (capturedValues[i]: any );
105- // const error = capturedValue.value;
106- // ctor.getDerivedStateFromCatch(error);
107- // }
99+ function callGetDerivedStateFromCatch ( ctor : any , capturedValues : Array < mixed > ) {
100+ const resultState = { } ;
101+ for ( let i = 0 ; i < capturedValues . length ; i ++ ) {
102+ const capturedValue : CapturedValue < mixed > = (capturedValues[i]: any);
103+ const error = capturedValue.value;
104+ const partialState = ctor.getDerivedStateFromCatch.call(null, error);
105+ if (partialState !== null && partialState !== undefined ) {
106+ Object . assign ( resultState , partialState ) ;
107+ }
108+ }
109+ return resultState ;
108110}
109111
110112export default function (
@@ -687,6 +689,8 @@ export default function(
687689 // ever the previously attempted to render - not the "current". However,
688690 // during componentDidUpdate we pass the "current" props.
689691
692+ // In order to support react-lifecycles-compat polyfilled components,
693+ // Unsafe lifecycles should not be invoked for any component with the new gDSFP.
690694 if (
691695 ( typeof instance . UNSAFE_componentWillReceiveProps === 'function' ||
692696 typeof instance . componentWillReceiveProps === 'function' ) &&
@@ -702,10 +706,20 @@ export default function(
702706 }
703707 }
704708
709+ let derivedStateFromProps ;
710+ if ( oldProps !== newProps ) {
711+ derivedStateFromProps = callGetDerivedStateFromProps (
712+ workInProgress ,
713+ instance ,
714+ newProps ,
715+ ) ;
716+ }
717+
705718 // Compute the next state using the memoized state and the update queue.
706719 const oldState = workInProgress . memoizedState ;
707720 // TODO: Previous state can be null.
708721 let newState ;
722+ let derivedStateFromCatch ;
709723 if ( workInProgress . updateQueue !== null ) {
710724 newState = processUpdateQueue (
711725 null ,
@@ -720,27 +734,42 @@ export default function(
720734 if (
721735 updateQueue !== null &&
722736 updateQueue . capturedValues !== null &&
723- typeof ctor . getDerivedStateFromCatch === 'function'
737+ ( enableGetDerivedStateFromCatch &&
738+ typeof ctor . getDerivedStateFromCatch === 'function' )
724739 ) {
725740 const capturedValues = updateQueue . capturedValues ;
726741 // Don't remove these from the update queue yet. We need them in
727742 // finishClassComponent. Do the reset there.
728743 // TODO: This is awkward. Refactor class components.
729744 // updateQueue.capturedValues = null;
730- callGetDerivedStateFromCatch ( ctor , capturedValues ) ;
731- newState = processUpdateQueue (
732- null ,
733- workInProgress ,
734- updateQueue ,
735- instance ,
736- newProps ,
737- renderExpirationTime ,
745+ derivedStateFromCatch = callGetDerivedStateFromCatch (
746+ ctor ,
747+ capturedValues ,
738748 ) ;
739749 }
740750 } else {
741751 newState = oldState ;
742752 }
743753
754+ if ( derivedStateFromProps !== null && derivedStateFromProps !== undefined ) {
755+ // Render-phase updates (like this) should not be added to the update queue,
756+ // So that multiple render passes do not enqueue multiple updates.
757+ // Instead, just synchronously merge the returned state into the instance.
758+ newState =
759+ newState === null || newState === undefined
760+ ? derivedStateFromProps
761+ : Object . assign ( { } , newState , derivedStateFromProps ) ;
762+ }
763+ if ( derivedStateFromCatch !== null && derivedStateFromCatch !== undefined ) {
764+ // Render-phase updates (like this) should not be added to the update queue,
765+ // So that multiple render passes do not enqueue multiple updates.
766+ // Instead, just synchronously merge the returned state into the instance.
767+ newState =
768+ newState === null || newState === undefined
769+ ? derivedStateFromCatch
770+ : Object . assign ( { } , newState , derivedStateFromCatch ) ;
771+ }
772+
744773 if (
745774 oldProps === newProps &&
746775 oldState === newState &&
@@ -752,7 +781,7 @@ export default function(
752781 ) {
753782 // If an update was already in progress, we should schedule an Update
754783 // effect even though we're bailing out, so that cWU/cDU are called.
755- if ( typeof instance . componentDidUpdate === 'function' ) {
784+ if ( typeof instance . componentDidMount === 'function' ) {
756785 workInProgress . effectTag |= Update ;
757786 }
758787 return false ;
@@ -768,45 +797,23 @@ export default function(
768797 ) ;
769798
770799 if ( shouldUpdate ) {
771- if ( __DEV__ ) {
772- if ( workInProgress . mode & StrictMode ) {
773- ReactStrictModeWarnings . recordUnsafeLifecycleWarnings (
774- workInProgress ,
775- instance ,
776- ) ;
777- }
778-
779- if ( warnAboutDeprecatedLifecycles ) {
780- ReactStrictModeWarnings . recordDeprecationWarnings (
781- workInProgress ,
782- instance ,
783- ) ;
784- }
785- }
786-
787800 // In order to support react-lifecycles-compat polyfilled components,
788801 // Unsafe lifecycles should not be invoked for any component with the new gDSFP.
789802 if (
790- ( typeof instance . UNSAFE_componentWillMount === 'function' ||
791- typeof instance . componentWillMount === 'function' ) &&
803+ ( typeof instance . UNSAFE_componentWillUpdate === 'function' ||
804+ typeof instance . componentWillUpdate === 'function' ) &&
792805 typeof ctor . getDerivedStateFromProps !== 'function'
793806 ) {
794- callComponentWillMount ( workInProgress , instance ) ;
795- // If we had additional state updates during this life-cycle, let's
796- // process them now.
797- const updateQueue = workInProgress . updateQueue ;
798- if ( updateQueue !== null ) {
799- instance . state = processUpdateQueue (
800- workInProgress . alternate ,
801- workInProgress ,
802- updateQueue ,
803- instance ,
804- newProps ,
805- renderExpirationTime ,
806- ) ;
807+ startPhaseTimer ( workInProgress , 'componentWillUpdate' ) ;
808+ if ( typeof instance . componentWillUpdate === 'function' ) {
809+ instance . componentWillUpdate ( newProps , newState , newContext ) ;
810+ }
811+ if ( typeof instance . UNSAFE_componentWillUpdate === 'function' ) {
812+ instance . UNSAFE_componentWillUpdate ( newProps , newState , newContext ) ;
807813 }
814+ stopPhaseTimer ( ) ;
808815 }
809- if ( typeof instance . componentDidMount === 'function' ) {
816+ if ( typeof instance . componentDidUpdate === 'function' ) {
810817 workInProgress . effectTag |= Update ;
811818 }
812819 } else {
@@ -868,9 +875,9 @@ export default function(
868875 }
869876 }
870877
871- let partialState ;
878+ let derivedStateFromProps ;
872879 if ( oldProps !== newProps ) {
873- partialState = callGetDerivedStateFromProps (
880+ derivedStateFromProps = callGetDerivedStateFromProps (
874881 workInProgress ,
875882 instance ,
876883 newProps ,
@@ -881,6 +888,7 @@ export default function(
881888 const oldState = workInProgress . memoizedState ;
882889 // TODO: Previous state can be null.
883890 let newState ;
891+ let derivedStateFromCatch ;
884892 if ( workInProgress . updateQueue !== null ) {
885893 newState = processUpdateQueue (
886894 current ,
@@ -895,35 +903,40 @@ export default function(
895903 if (
896904 updateQueue !== null &&
897905 updateQueue . capturedValues !== null &&
898- typeof ctor . getDerivedStateFromCatch === 'function'
906+ ( enableGetDerivedStateFromCatch &&
907+ typeof ctor . getDerivedStateFromCatch === 'function' )
899908 ) {
900909 const capturedValues = updateQueue . capturedValues ;
901910 // Don't remove these from the update queue yet. We need them in
902911 // finishClassComponent. Do the reset there.
903912 // TODO: This is awkward. Refactor class components.
904913 // updateQueue.capturedValues = null;
905- callGetDerivedStateFromCatch ( ctor , capturedValues ) ;
906- newState = processUpdateQueue (
907- null ,
908- workInProgress ,
909- updateQueue ,
910- instance ,
911- newProps ,
912- renderExpirationTime ,
914+ derivedStateFromCatch = callGetDerivedStateFromCatch (
915+ ctor ,
916+ capturedValues ,
913917 ) ;
914918 }
915919 } else {
916920 newState = oldState ;
917921 }
918922
919- if ( partialState !== null && partialState !== undefined ) {
923+ if ( derivedStateFromProps !== null && derivedStateFromProps !== undefined ) {
924+ // Render-phase updates (like this) should not be added to the update queue,
925+ // So that multiple render passes do not enqueue multiple updates.
926+ // Instead, just synchronously merge the returned state into the instance.
927+ newState =
928+ newState === null || newState === undefined
929+ ? derivedStateFromProps
930+ : Object . assign ( { } , newState , derivedStateFromProps ) ;
931+ }
932+ if ( derivedStateFromCatch !== null && derivedStateFromCatch !== undefined ) {
920933 // Render-phase updates (like this) should not be added to the update queue,
921934 // So that multiple render passes do not enqueue multiple updates.
922935 // Instead, just synchronously merge the returned state into the instance.
923936 newState =
924937 newState === null || newState === undefined
925- ? partialState
926- : Object . assign ( { } , newState , partialState ) ;
938+ ? derivedStateFromCatch
939+ : Object . assign ( { } , newState , derivedStateFromCatch ) ;
927940 }
928941
929942 if (
0 commit comments