@@ -225,18 +225,6 @@ const callComponentWillUnmountWithTimer = function(current, instance) {
225225 }
226226} ;
227227
228- // Capture errors so they don't interrupt mounting.
229- function safelyCallCommitHookLayoutEffectListMount (
230- current : Fiber ,
231- nearestMountedAncestor : Fiber | null ,
232- ) {
233- try {
234- commitHookEffectListMount ( HookLayout , current ) ;
235- } catch ( error ) {
236- captureCommitPhaseError ( current , nearestMountedAncestor , error ) ;
237- }
238- }
239-
240228// Capture errors so they don't interrupt unmounting.
241229function safelyCallComponentWillUnmount (
242230 current : Fiber ,
@@ -250,19 +238,6 @@ function safelyCallComponentWillUnmount(
250238 }
251239}
252240
253- // Capture errors so they don't interrupt mounting.
254- function safelyCallComponentDidMount (
255- current : Fiber ,
256- nearestMountedAncestor : Fiber | null ,
257- instance : any ,
258- ) {
259- try {
260- instance . componentDidMount ( ) ;
261- } catch ( error ) {
262- captureCommitPhaseError ( current , nearestMountedAncestor , error ) ;
263- }
264- }
265-
266241// Capture errors so they don't interrupt mounting.
267242function safelyAttachRef ( current : Fiber , nearestMountedAncestor : Fiber | null ) {
268243 try {
@@ -706,7 +681,7 @@ export function commitPassiveEffectDurations(
706681 }
707682}
708683
709- function commitHookLayoutEffects ( finishedWork : Fiber ) {
684+ function commitHookLayoutEffects ( finishedWork : Fiber , hookFlags : HookFlags ) {
710685 // At this point layout effects have already been destroyed (during mutation phase).
711686 // This is done to prevent sibling component effects from interfering with each other,
712687 // e.g. a destroy function in one component should never override a ref set
@@ -718,14 +693,14 @@ function commitHookLayoutEffects(finishedWork: Fiber) {
718693 ) {
719694 try {
720695 startLayoutEffectTimer ( ) ;
721- commitHookEffectListMount ( HookLayout | HookHasEffect , finishedWork ) ;
696+ commitHookEffectListMount ( hookFlags , finishedWork ) ;
722697 } catch ( error ) {
723698 captureCommitPhaseError ( finishedWork , finishedWork . return , error ) ;
724699 }
725700 recordLayoutEffectDuration ( finishedWork ) ;
726701 } else {
727702 try {
728- commitHookEffectListMount ( HookLayout | HookHasEffect , finishedWork ) ;
703+ commitHookEffectListMount ( hookFlags , finishedWork ) ;
729704 } catch ( error ) {
730705 captureCommitPhaseError ( finishedWork , finishedWork . return , error ) ;
731706 }
@@ -853,7 +828,7 @@ function commitClassLayoutLifecycles(
853828 }
854829}
855830
856- function commitClassCallbacks ( finishedWork : Fiber , current : Fiber | null ) {
831+ function commitClassCallbacks ( finishedWork : Fiber ) {
857832 // TODO: I think this is now always non-null by the time it reaches the
858833 // commit phase. Consider removing the type check.
859834 const updateQueue : UpdateQueue < * > | null = ( finishedWork . updateQueue : any ) ;
@@ -897,7 +872,7 @@ function commitClassCallbacks(finishedWork: Fiber, current: Fiber | null) {
897872 }
898873}
899874
900- function commitHostComponentMount ( finishedWork : Fiber , current : Fiber | null ) {
875+ function commitHostComponentMount ( finishedWork : Fiber ) {
901876 const type = finishedWork . type ;
902877 const props = finishedWork . memoizedProps ;
903878 const instance : Instance = finishedWork . stateNode ;
@@ -978,6 +953,8 @@ function commitLayoutEffectOnFiber(
978953 finishedWork : Fiber ,
979954 committedLanes : Lanes ,
980955) : void {
956+ // When updating this function, also update reappearLayoutEffects, which does
957+ // most of the same things when an offscreen tree goes from hidden -> visible.
981958 const flags = finishedWork . flags ;
982959 switch ( finishedWork . tag ) {
983960 case FunctionComponent :
@@ -989,9 +966,7 @@ function commitLayoutEffectOnFiber(
989966 committedLanes ,
990967 ) ;
991968 if ( flags & Update ) {
992- if ( ! offscreenSubtreeWasHidden ) {
993- commitHookLayoutEffects ( finishedWork ) ;
994- }
969+ commitHookLayoutEffects ( finishedWork , HookLayout | HookHasEffect ) ;
995970 }
996971 break ;
997972 }
@@ -1002,19 +977,15 @@ function commitLayoutEffectOnFiber(
1002977 committedLanes ,
1003978 ) ;
1004979 if ( flags & Update ) {
1005- if ( ! offscreenSubtreeWasHidden ) {
1006- commitClassLayoutLifecycles ( finishedWork , current ) ;
1007- }
980+ commitClassLayoutLifecycles ( finishedWork , current ) ;
1008981 }
1009982
1010983 if ( flags & Callback ) {
1011- commitClassCallbacks ( finishedWork , current ) ;
984+ commitClassCallbacks ( finishedWork ) ;
1012985 }
1013986
1014987 if ( flags & Ref ) {
1015- if ( ! offscreenSubtreeWasHidden ) {
1016- safelyAttachRef ( finishedWork , finishedWork . return ) ;
1017- }
988+ safelyAttachRef ( finishedWork , finishedWork . return ) ;
1018989 }
1019990 break ;
1020991 }
@@ -1063,13 +1034,11 @@ function commitLayoutEffectOnFiber(
10631034 // These effects should only be committed when components are first mounted,
10641035 // aka when there is no current/alternate.
10651036 if ( current === null && flags & Update ) {
1066- commitHostComponentMount ( finishedWork , current ) ;
1037+ commitHostComponentMount ( finishedWork ) ;
10671038 }
10681039
10691040 if ( flags & Ref ) {
1070- if ( ! offscreenSubtreeWasHidden ) {
1071- safelyAttachRef ( finishedWork , finishedWork . return ) ;
1072- }
1041+ safelyAttachRef ( finishedWork , finishedWork . return ) ;
10731042 }
10741043 break ;
10751044 }
@@ -1117,19 +1086,25 @@ function commitLayoutEffectOnFiber(
11171086 offscreenSubtreeWasHidden = newOffscreenSubtreeWasHidden ;
11181087
11191088 if ( offscreenSubtreeWasHidden && ! prevOffscreenSubtreeWasHidden ) {
1120- // This is the root of a reappearing boundary. Turn its layout
1121- // effects back on.
1122- recursivelyTraverseReappearLayoutEffects ( finishedWork ) ;
1089+ // This is the root of a reappearing boundary. As we continue
1090+ // traversing the layout effects, we must also re-mount layout
1091+ // effects that were unmounted when the Offscreen subtree was
1092+ // hidden. So this is a superset of the normal commitLayoutEffects.
1093+ const includeWorkInProgressEffects =
1094+ ( finishedWork . subtreeFlags & LayoutMask ) !== NoFlags ;
1095+ recursivelyTraverseReappearLayoutEffects (
1096+ finishedRoot ,
1097+ finishedWork ,
1098+ committedLanes ,
1099+ includeWorkInProgressEffects ,
1100+ ) ;
1101+ } else {
1102+ recursivelyTraverseLayoutEffects (
1103+ finishedRoot ,
1104+ finishedWork ,
1105+ committedLanes ,
1106+ ) ;
11231107 }
1124-
1125- // TODO: We shouldn't traverse twice when reappearing layout effects.
1126- // Move this into the else block of the above if statement, and modify
1127- // reappearLayoutEffects to fire regular layout effects, too.
1128- recursivelyTraverseLayoutEffects (
1129- finishedRoot ,
1130- finishedWork ,
1131- committedLanes ,
1132- ) ;
11331108 offscreenSubtreeIsHidden = prevOffscreenSubtreeIsHidden ;
11341109 offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden ;
11351110 }
@@ -2723,90 +2698,177 @@ function recursivelyTraverseDisappearLayoutEffects(parentFiber: Fiber) {
27232698 }
27242699}
27252700
2726- function reappearLayoutEffects ( finishedWork : Fiber ) {
2701+ function reappearLayoutEffects (
2702+ finishedRoot : FiberRoot ,
2703+ current : Fiber | null ,
2704+ finishedWork : Fiber ,
2705+ committedLanes : Lanes ,
2706+ // This function visits both newly finished work and nodes that were re-used
2707+ // from a previously committed tree. We cannot check non-static flags if the
2708+ // node was reused.
2709+ includeWorkInProgressEffects : boolean ,
2710+ ) {
27272711 // Turn on layout effects in a tree that previously disappeared.
2728- // TODO (Offscreen) Check: flags & LayoutStatic
2712+ const flags = finishedWork . flags ;
27292713 switch ( finishedWork . tag ) {
27302714 case FunctionComponent :
27312715 case ForwardRef :
27322716 case SimpleMemoComponent : {
2733- recursivelyTraverseReappearLayoutEffects ( finishedWork ) ;
2734-
2735- // TODO: Check for LayoutStatic flag
2736- if (
2737- enableProfilerTimer &&
2738- enableProfilerCommitHooks &&
2739- finishedWork . mode & ProfileMode
2740- ) {
2741- try {
2742- startLayoutEffectTimer ( ) ;
2743- safelyCallCommitHookLayoutEffectListMount (
2744- finishedWork ,
2745- finishedWork . return ,
2746- ) ;
2747- } finally {
2748- recordLayoutEffectDuration ( finishedWork ) ;
2749- }
2750- } else {
2751- safelyCallCommitHookLayoutEffectListMount (
2752- finishedWork ,
2753- finishedWork . return ,
2754- ) ;
2755- }
2717+ recursivelyTraverseReappearLayoutEffects (
2718+ finishedRoot ,
2719+ finishedWork ,
2720+ committedLanes ,
2721+ includeWorkInProgressEffects ,
2722+ ) ;
2723+ // TODO: Check flags & LayoutStatic
2724+ commitHookLayoutEffects ( finishedWork , HookLayout ) ;
27562725 break ;
27572726 }
27582727 case ClassComponent : {
2759- recursivelyTraverseReappearLayoutEffects ( finishedWork ) ;
2728+ recursivelyTraverseReappearLayoutEffects (
2729+ finishedRoot ,
2730+ finishedWork ,
2731+ committedLanes ,
2732+ includeWorkInProgressEffects ,
2733+ ) ;
27602734
2761- const instance = finishedWork . stateNode ;
27622735 // TODO: Check for LayoutStatic flag
2736+ const instance = finishedWork . stateNode ;
27632737 if ( typeof instance . componentDidMount === 'function' ) {
2764- safelyCallComponentDidMount (
2765- finishedWork ,
2766- finishedWork . return ,
2767- instance ,
2768- ) ;
2738+ try {
2739+ instance . componentDidMount ( ) ;
2740+ } catch ( error ) {
2741+ captureCommitPhaseError ( finishedWork , finishedWork . return , error ) ;
2742+ }
27692743 }
2770- // TODO: Check for RefStatic flag
2771- safelyAttachRef ( finishedWork , finishedWork . return ) ;
2744+
2745+ // Commit any callbacks that would have fired while the component
2746+ // was hidden.
27722747 const updateQueue : UpdateQueue <
27732748 * ,
27742749 > | null = ( finishedWork . updateQueue : any ) ;
27752750 if ( updateQueue !== null ) {
27762751 commitHiddenCallbacks ( updateQueue , instance ) ;
27772752 }
2753+
2754+ // If this is newly finished work, check for setState callbacks
2755+ if ( includeWorkInProgressEffects && flags & Callback ) {
2756+ commitClassCallbacks ( finishedWork ) ;
2757+ }
2758+
2759+ // TODO: Check flags & RefStatic
2760+ safelyAttachRef ( finishedWork , finishedWork . return ) ;
27782761 break ;
27792762 }
2763+ // Unlike commitLayoutEffectsOnFiber, we don't need to handle HostRoot
2764+ // because this function only visits nodes that are inside an
2765+ // Offscreen fiber.
2766+ // case HostRoot: {
2767+ // ...
2768+ // }
27802769 case HostComponent : {
2781- recursivelyTraverseReappearLayoutEffects ( finishedWork ) ;
2770+ recursivelyTraverseReappearLayoutEffects (
2771+ finishedRoot ,
2772+ finishedWork ,
2773+ committedLanes ,
2774+ includeWorkInProgressEffects ,
2775+ ) ;
27822776
2783- // TODO: Check for RefStatic flag
2777+ // Renderers may schedule work to be done after host components are mounted
2778+ // (eg DOM renderer may schedule auto-focus for inputs and form controls).
2779+ // These effects should only be committed when components are first mounted,
2780+ // aka when there is no current/alternate.
2781+ if ( includeWorkInProgressEffects && current === null && flags & Update ) {
2782+ commitHostComponentMount ( finishedWork ) ;
2783+ }
2784+
2785+ // TODO: Check flags & Ref
27842786 safelyAttachRef ( finishedWork , finishedWork . return ) ;
27852787 break ;
27862788 }
2789+ case Profiler : {
2790+ recursivelyTraverseReappearLayoutEffects (
2791+ finishedRoot ,
2792+ finishedWork ,
2793+ committedLanes ,
2794+ includeWorkInProgressEffects ,
2795+ ) ;
2796+ // TODO: Figure out how Profiler updates should work with Offscreen
2797+ if ( includeWorkInProgressEffects && flags & Update ) {
2798+ commitProfilerUpdate ( finishedWork , current ) ;
2799+ }
2800+ break ;
2801+ }
2802+ case SuspenseComponent : {
2803+ recursivelyTraverseReappearLayoutEffects (
2804+ finishedRoot ,
2805+ finishedWork ,
2806+ committedLanes ,
2807+ includeWorkInProgressEffects ,
2808+ ) ;
2809+
2810+ // TODO: Figure out how Suspense hydration callbacks should work
2811+ // with Offscreen.
2812+ if ( includeWorkInProgressEffects && flags & Update ) {
2813+ commitSuspenseHydrationCallbacks ( finishedRoot , finishedWork ) ;
2814+ }
2815+ break ;
2816+ }
27872817 case OffscreenComponent : {
2788- const isHidden = finishedWork . memoizedState !== null ;
2818+ const offscreenState : OffscreenState = finishedWork . memoizedState ;
2819+ const isHidden = offscreenState !== null ;
27892820 if ( isHidden ) {
27902821 // Nested Offscreen tree is still hidden. Don't re-appear its effects.
27912822 } else {
2792- recursivelyTraverseReappearLayoutEffects ( finishedWork ) ;
2823+ recursivelyTraverseReappearLayoutEffects (
2824+ finishedRoot ,
2825+ finishedWork ,
2826+ committedLanes ,
2827+ includeWorkInProgressEffects ,
2828+ ) ;
27932829 }
27942830 break ;
27952831 }
27962832 default : {
2797- recursivelyTraverseReappearLayoutEffects ( finishedWork ) ;
2833+ recursivelyTraverseReappearLayoutEffects (
2834+ finishedRoot ,
2835+ finishedWork ,
2836+ committedLanes ,
2837+ includeWorkInProgressEffects ,
2838+ ) ;
27982839 break ;
27992840 }
28002841 }
28012842}
28022843
2803- function recursivelyTraverseReappearLayoutEffects ( parentFiber : Fiber ) {
2844+ function recursivelyTraverseReappearLayoutEffects (
2845+ finishedRoot : FiberRoot ,
2846+ parentFiber : Fiber ,
2847+ committedLanes : Lanes ,
2848+ includeWorkInProgressEffects : boolean ,
2849+ ) {
2850+ // This function visits both newly finished work and nodes that were re-used
2851+ // from a previously committed tree. We cannot check non-static flags if the
2852+ // node was reused.
2853+ const childShouldIncludeWorkInProgressEffects =
2854+ includeWorkInProgressEffects &&
2855+ ( parentFiber . subtreeFlags & LayoutMask ) !== NoFlags ;
2856+
28042857 // TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic)
2858+ const prevDebugFiber = getCurrentDebugFiberInDEV ( ) ;
28052859 let child = parentFiber . child ;
28062860 while ( child !== null ) {
2807- reappearLayoutEffects ( child ) ;
2861+ const current = child . alternate ;
2862+ reappearLayoutEffects (
2863+ finishedRoot ,
2864+ current ,
2865+ child ,
2866+ committedLanes ,
2867+ childShouldIncludeWorkInProgressEffects ,
2868+ ) ;
28082869 child = child . sibling ;
28092870 }
2871+ setCurrentDebugFiberInDEV ( prevDebugFiber ) ;
28102872}
28112873
28122874export function commitPassiveMountEffects (
0 commit comments