@@ -81,8 +81,6 @@ import {
81
81
MutationMask ,
82
82
LayoutMask ,
83
83
PassiveMask ,
84
- LayoutStatic ,
85
- RefStatic ,
86
84
} from './ReactFiberFlags' ;
87
85
import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber' ;
88
86
import invariant from 'shared/invariant' ;
@@ -1027,14 +1025,18 @@ function hideOrUnhideAllChildren(finishedWork, isHidden) {
1027
1025
const current = finishedWork . alternate ;
1028
1026
const wasHidden = current !== null && current . memoizedState !== null ;
1029
1027
1028
+ // Only hide the top-most host nodes.
1029
+ let hiddenHostSubtreeRoot = null ;
1030
+
1030
1031
if ( supportsMutation ) {
1031
1032
// We only have the top Fiber that was inserted but we need to recurse down its
1032
1033
// children to find all the terminal nodes.
1033
1034
let node : Fiber = finishedWork ;
1034
1035
while ( true ) {
1035
1036
if ( node . tag === HostComponent ) {
1036
1037
const instance = node . stateNode ;
1037
- if ( isHidden ) {
1038
+ if ( isHidden && hiddenHostSubtreeRoot === null ) {
1039
+ hiddenHostSubtreeRoot = node ;
1038
1040
hideInstance ( instance ) ;
1039
1041
} else {
1040
1042
unhideInstance ( node . stateNode , node . memoizedProps ) ;
@@ -1043,24 +1045,21 @@ function hideOrUnhideAllChildren(finishedWork, isHidden) {
1043
1045
if ( enableSuspenseLayoutEffectSemantics && isModernRoot ) {
1044
1046
// This method is called during mutation; it should detach refs within a hidden subtree.
1045
1047
// 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 ) ;
1050
1051
}
1051
1052
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 ) {
1056
1055
node . child . return = node ;
1057
1056
node = node . child ;
1058
1057
continue ;
1059
1058
}
1060
1059
}
1061
1060
} else if ( node . tag === HostText ) {
1062
1061
const instance = node . stateNode ;
1063
- if ( isHidden ) {
1062
+ if ( isHidden && hiddenHostSubtreeRoot === null ) {
1064
1063
hideTextInstance ( instance ) ;
1065
1064
} else {
1066
1065
unhideTextInstance ( instance , node . memoizedProps ) ;
@@ -1075,43 +1074,42 @@ function hideOrUnhideAllChildren(finishedWork, isHidden) {
1075
1074
// Don't search any deeper. This tree should remain hidden.
1076
1075
} else if ( enableSuspenseLayoutEffectSemantics && isModernRoot ) {
1077
1076
// 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 ( ) ;
1098
1092
commitHookEffectListUnmount ( HookLayout , node , finishedWork ) ;
1093
+ } finally {
1094
+ recordLayoutEffectDuration ( node ) ;
1099
1095
}
1096
+ } else {
1097
+ commitHookEffectListUnmount ( HookLayout , node , finishedWork ) ;
1100
1098
}
1101
- break ;
1102
1099
}
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 ) ;
1112
1110
}
1113
- break ;
1114
1111
}
1112
+ break ;
1115
1113
}
1116
1114
}
1117
1115
@@ -1133,8 +1131,18 @@ function hideOrUnhideAllChildren(finishedWork, isHidden) {
1133
1131
if ( node . return === null || node . return === finishedWork ) {
1134
1132
return ;
1135
1133
}
1134
+
1135
+ if ( hiddenHostSubtreeRoot === node ) {
1136
+ hiddenHostSubtreeRoot = null ;
1137
+ }
1138
+
1136
1139
node = node . return ;
1137
1140
}
1141
+
1142
+ if ( hiddenHostSubtreeRoot === node ) {
1143
+ hiddenHostSubtreeRoot = null ;
1144
+ }
1145
+
1138
1146
node . sibling . return = node . return ;
1139
1147
node = node . sibling ;
1140
1148
}
@@ -2378,11 +2386,9 @@ function commitLayoutEffects_begin(
2378
2386
if ( enableSuspenseLayoutEffectSemantics && isModernRoot ) {
2379
2387
const visibilityChanged =
2380
2388
! 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 ) {
2386
2392
// We've just shown or hidden a Offscreen tree that contains layout effects.
2387
2393
// We only enter this code path for subtrees that are updated,
2388
2394
// because newly mounted ones would pass the LayoutMask check above.
@@ -2417,42 +2423,42 @@ function commitLayoutMountEffects_complete(
2417
2423
// Inside of an Offscreen subtree that changed visibility during this commit.
2418
2424
// If this subtree was hidden, layout effects will have already been destroyed (during mutation phase)
2419
2425
// 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 ( ) ;
2437
2438
safelyCallCommitHookLayoutEffectListMount ( fiber , fiber . return ) ;
2439
+ } finally {
2440
+ recordLayoutEffectDuration ( fiber ) ;
2438
2441
}
2439
- break ;
2442
+ } else {
2443
+ safelyCallCommitHookLayoutEffectListMount ( fiber , fiber . return ) ;
2440
2444
}
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' ) {
2443
2450
safelyCallComponentDidMount ( fiber , fiber . return , instance ) ;
2444
- break ;
2445
2451
}
2452
+ break ;
2446
2453
}
2447
2454
}
2448
2455
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 ;
2456
2462
}
2457
2463
} else if ( ( fiber . flags & LayoutMask ) !== NoFlags ) {
2458
2464
const current = fiber . alternate ;
0 commit comments