@@ -81,8 +81,6 @@ import {
8181 MutationMask ,
8282 LayoutMask ,
8383 PassiveMask ,
84- LayoutStatic ,
85- RefStatic ,
8684} from './ReactFiberFlags' ;
8785import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber' ;
8886import invariant from 'shared/invariant' ;
@@ -1027,14 +1025,18 @@ function hideOrUnhideAllChildren(finishedWork, isHidden) {
10271025 const current = finishedWork . alternate ;
10281026 const wasHidden = current !== null && current . memoizedState !== null ;
10291027
1028+ // Only hide the top-most host nodes.
1029+ let hiddenHostSubtreeRoot = null ;
1030+
10301031 if ( supportsMutation ) {
10311032 // We only have the top Fiber that was inserted but we need to recurse down its
10321033 // children to find all the terminal nodes.
10331034 let node : Fiber = finishedWork ;
10341035 while ( true ) {
10351036 if ( node . tag === HostComponent ) {
10361037 const instance = node . stateNode ;
1037- if ( isHidden ) {
1038+ if ( isHidden && hiddenHostSubtreeRoot === null ) {
1039+ hiddenHostSubtreeRoot = node ;
10381040 hideInstance ( instance ) ;
10391041 } else {
10401042 unhideInstance ( node . stateNode , node . memoizedProps ) ;
@@ -1043,24 +1045,21 @@ function hideOrUnhideAllChildren(finishedWork, isHidden) {
10431045 if ( enableSuspenseLayoutEffectSemantics && isModernRoot ) {
10441046 // This method is called during mutation; it should detach refs within a hidden subtree.
10451047 // Attaching refs should be done elsewhere though (during layout).
1046- if ( ( node . flags & RefStatic ) !== NoFlags ) {
1047- if ( isHidden ) {
1048- safelyDetachRef ( node , finishedWork ) ;
1049- }
1048+ // TODO (Offscreen) Also check: flags & RefStatic
1049+ if ( isHidden ) {
1050+ safelyDetachRef ( node , finishedWork ) ;
10501051 }
10511052
1052- if (
1053- ( node . subtreeFlags & ( RefStatic | LayoutStatic ) ) !== NoFlags &&
1054- node . child !== null
1055- ) {
1053+ // TODO (Offscreen) Also check: subtreeFlags & (RefStatic | LayoutStatic)
1054+ if ( node . child !== null ) {
10561055 node . child . return = node ;
10571056 node = node . child ;
10581057 continue ;
10591058 }
10601059 }
10611060 } else if ( node . tag === HostText ) {
10621061 const instance = node . stateNode ;
1063- if ( isHidden ) {
1062+ if ( isHidden && hiddenHostSubtreeRoot === null ) {
10641063 hideTextInstance ( instance ) ;
10651064 } else {
10661065 unhideTextInstance ( instance , node . memoizedProps ) ;
@@ -1075,43 +1074,42 @@ function hideOrUnhideAllChildren(finishedWork, isHidden) {
10751074 // Don't search any deeper. This tree should remain hidden.
10761075 } else if ( enableSuspenseLayoutEffectSemantics && isModernRoot ) {
10771076 // When a mounted Suspense subtree gets hidden again, destroy any nested layout effects.
1078- if ( ( node . flags & ( RefStatic | LayoutStatic ) ) !== NoFlags ) {
1079- switch ( node . tag ) {
1080- case FunctionComponent :
1081- case ForwardRef :
1082- case MemoComponent :
1083- case SimpleMemoComponent : {
1084- // Note that refs are attached by the useImperativeHandle() hook, not by commitAttachRef()
1085- if ( isHidden && ! wasHidden ) {
1086- if (
1087- enableProfilerTimer &&
1088- enableProfilerCommitHooks &&
1089- node . mode & ProfileMode
1090- ) {
1091- try {
1092- startLayoutEffectTimer ( ) ;
1093- commitHookEffectListUnmount ( HookLayout , node , finishedWork ) ;
1094- } finally {
1095- recordLayoutEffectDuration ( node ) ;
1096- }
1097- } else {
1077+ // TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic)
1078+ switch ( node . tag ) {
1079+ case FunctionComponent :
1080+ case ForwardRef :
1081+ case MemoComponent :
1082+ case SimpleMemoComponent : {
1083+ // Note that refs are attached by the useImperativeHandle() hook, not by commitAttachRef()
1084+ if ( isHidden && ! wasHidden ) {
1085+ if (
1086+ enableProfilerTimer &&
1087+ enableProfilerCommitHooks &&
1088+ node . mode & ProfileMode
1089+ ) {
1090+ try {
1091+ startLayoutEffectTimer ( ) ;
10981092 commitHookEffectListUnmount ( HookLayout , node , finishedWork ) ;
1093+ } finally {
1094+ recordLayoutEffectDuration ( node ) ;
10991095 }
1096+ } else {
1097+ commitHookEffectListUnmount ( HookLayout , node , finishedWork ) ;
11001098 }
1101- break ;
11021099 }
1103- case ClassComponent : {
1104- if ( isHidden && ! wasHidden ) {
1105- if ( ( node . flags & RefStatic ) !== NoFlags ) {
1106- safelyDetachRef ( node , finishedWork ) ;
1107- }
1108- const instance = node . stateNode ;
1109- if ( typeof instance . componentWillUnmount === 'function' ) {
1110- safelyCallComponentWillUnmount ( node , finishedWork , instance ) ;
1111- }
1100+ break ;
1101+ }
1102+ case ClassComponent : {
1103+ if ( isHidden && ! wasHidden ) {
1104+ // TODO (Offscreen) Check: flags & RefStatic
1105+ safelyDetachRef ( node , finishedWork ) ;
1106+
1107+ const instance = node . stateNode ;
1108+ if ( typeof instance . componentWillUnmount === 'function' ) {
1109+ safelyCallComponentWillUnmount ( node , finishedWork , instance ) ;
11121110 }
1113- break ;
11141111 }
1112+ break ;
11151113 }
11161114 }
11171115
@@ -1133,8 +1131,18 @@ function hideOrUnhideAllChildren(finishedWork, isHidden) {
11331131 if ( node . return === null || node . return === finishedWork ) {
11341132 return ;
11351133 }
1134+
1135+ if ( hiddenHostSubtreeRoot === node ) {
1136+ hiddenHostSubtreeRoot = null ;
1137+ }
1138+
11361139 node = node . return ;
11371140 }
1141+
1142+ if ( hiddenHostSubtreeRoot === node ) {
1143+ hiddenHostSubtreeRoot = null ;
1144+ }
1145+
11381146 node . sibling . return = node . return ;
11391147 node = node . sibling ;
11401148 }
@@ -2378,11 +2386,9 @@ function commitLayoutEffects_begin(
23782386 if ( enableSuspenseLayoutEffectSemantics && isModernRoot ) {
23792387 const visibilityChanged =
23802388 ! offscreenSubtreeIsHidden && offscreenSubtreeWasHidden ;
2381- if (
2382- visibilityChanged &&
2383- ( fiber . subtreeFlags & LayoutStatic ) !== NoFlags &&
2384- firstChild !== null
2385- ) {
2389+
2390+ // TODO (Offscreen) Also check: subtreeFlags & LayoutStatic
2391+ if ( visibilityChanged && firstChild !== null ) {
23862392 // We've just shown or hidden a Offscreen tree that contains layout effects.
23872393 // We only enter this code path for subtrees that are updated,
23882394 // because newly mounted ones would pass the LayoutMask check above.
@@ -2417,42 +2423,42 @@ function commitLayoutMountEffects_complete(
24172423 // Inside of an Offscreen subtree that changed visibility during this commit.
24182424 // If this subtree was hidden, layout effects will have already been destroyed (during mutation phase)
24192425 // but if it was just shown, we need to (re)create the effects now.
2420- if ( ( fiber . flags & LayoutStatic ) !== NoFlags ) {
2421- switch ( fiber . tag ) {
2422- case FunctionComponent :
2423- case ForwardRef :
2424- case SimpleMemoComponent : {
2425- if (
2426- enableProfilerTimer &&
2427- enableProfilerCommitHooks &&
2428- fiber . mode & ProfileMode
2429- ) {
2430- try {
2431- startLayoutEffectTimer ( ) ;
2432- safelyCallCommitHookLayoutEffectListMount ( fiber , fiber . return ) ;
2433- } finally {
2434- recordLayoutEffectDuration ( fiber ) ;
2435- }
2436- } else {
2426+ // TODO (Offscreen) Check: flags & LayoutStatic
2427+ switch ( fiber . tag ) {
2428+ case FunctionComponent :
2429+ case ForwardRef :
2430+ case SimpleMemoComponent : {
2431+ if (
2432+ enableProfilerTimer &&
2433+ enableProfilerCommitHooks &&
2434+ fiber . mode & ProfileMode
2435+ ) {
2436+ try {
2437+ startLayoutEffectTimer ( ) ;
24372438 safelyCallCommitHookLayoutEffectListMount ( fiber , fiber . return ) ;
2439+ } finally {
2440+ recordLayoutEffectDuration ( fiber ) ;
24382441 }
2439- break ;
2442+ } else {
2443+ safelyCallCommitHookLayoutEffectListMount ( fiber , fiber . return ) ;
24402444 }
2441- case ClassComponent : {
2442- const instance = fiber . stateNode ;
2445+ break ;
2446+ }
2447+ case ClassComponent : {
2448+ const instance = fiber . stateNode ;
2449+ if ( typeof instance . componentDidMount === 'function' ) {
24432450 safelyCallComponentDidMount ( fiber , fiber . return , instance ) ;
2444- break ;
24452451 }
2452+ break ;
24462453 }
24472454 }
24482455
2449- if ( ( fiber . flags & RefStatic ) !== NoFlags ) {
2450- switch ( fiber . tag ) {
2451- case ClassComponent :
2452- case HostComponent :
2453- safelyAttachRef ( fiber , fiber . return ) ;
2454- break ;
2455- }
2456+ // TODO (Offscreen) Check flags & RefStatic
2457+ switch ( fiber . tag ) {
2458+ case ClassComponent :
2459+ case HostComponent :
2460+ safelyAttachRef ( fiber , fiber . return ) ;
2461+ break ;
24562462 }
24572463 } else if ( ( fiber . flags & LayoutMask ) !== NoFlags ) {
24582464 const current = fiber . alternate ;
0 commit comments