288
import {markIndicatorHandled} from './ReactFiberRootScheduler';
289
import type {Flags} from './ReactFiberFlags';
290
291
+type LayoutEffectTraversalFlags = number;
292
+
293
+const NoLayoutEffectTraversalFlags = /* */ 0b00;
294
+const IncludeWorkInProgressEffects = /* */ 0b01;
295
+const IncludeHostSingletons = /* */ 0b10;
296
+
297
// Used during the commit phase to track the state of the Offscreen component stack.
298
// Allows us to avoid traversing the return path to find the nearest Offscreen ancestor.
299
let offscreenSubtreeIsHidden: boolean = false;
801
// traversing the layout effects, we must also re-mount layout
802
// effects that were unmounted when the Offscreen subtree was
803
// hidden. So this is a superset of the normal commitLayoutEffects.
798
- const includeWorkInProgressEffects =
799
- (finishedWork.subtreeFlags & LayoutMask) !== NoFlags;
804
+ let layoutEffectTraversalFlags: LayoutEffectTraversalFlags;
805
+ // $FlowFixMe[constant-condition]
806
+ if (supportsSingletons) {
807
+ layoutEffectTraversalFlags = IncludeHostSingletons;
808
+ } else {
809
+ layoutEffectTraversalFlags = NoLayoutEffectTraversalFlags;
810
+ }
811
+ if ((finishedWork.subtreeFlags & LayoutMask) !== NoFlags) {
812
+ layoutEffectTraversalFlags |= IncludeWorkInProgressEffects;
813
+ }
814
recursivelyTraverseReappearLayoutEffects(
815
finishedRoot,
816
finishedWork,
803
- includeWorkInProgressEffects,
817
+ layoutEffectTraversalFlags,
818
);
819
if (
820
enableProfilerTimer &&
2595
(finishedWork.mode & ConcurrentMode) !== NoMode
2596
) {
2597
// Disappear the layout effects of all the children
2584
- recursivelyTraverseDisappearLayoutEffects(finishedWork);
2598
+ let layoutEffectTraversalFlags: LayoutEffectTraversalFlags;
2599
+ // $FlowFixMe[constant-condition]
2600
+ if (supportsSingletons) {
2601
+ layoutEffectTraversalFlags = IncludeHostSingletons;
2602
+ } else {
2603
+ layoutEffectTraversalFlags = NoLayoutEffectTraversalFlags;
2604
+ }
2605
+ recursivelyTraverseDisappearLayoutEffects(
2606
+ finishedWork,
2607
+ layoutEffectTraversalFlags,
2608
+ );
2609
2610
if (
2611
enableProfilerTimer &&
3031
}
3032
}
3033
3010
-export function disappearLayoutEffects(finishedWork: Fiber) {
3034
+export function disappearLayoutEffectsForDEVValidation(finishedWork: Fiber) {
3035
+ if (__DEV__) {
3036
+ disappearLayoutEffects(finishedWork, NoLayoutEffectTraversalFlags);
3037
+ }
3038
+}
3039
+
3040
+function disappearLayoutEffects(
3041
+ finishedWork: Fiber,
3042
+ layoutEffectTraversalFlags: LayoutEffectTraversalFlags,
3043
+) {
3044
const prevEffectStart = pushComponentEffectStart();
3045
const prevEffectDuration = pushComponentEffectDuration();
3046
const prevEffectErrors = pushComponentEffectErrors();
3056
finishedWork.return,
3057
HookLayout,
3058
);
3026
- recursivelyTraverseDisappearLayoutEffects(finishedWork);
3059
+ recursivelyTraverseDisappearLayoutEffects(
3060
+ finishedWork,
3061
+ layoutEffectTraversalFlags,
3062
+ );
3063
break;
3064
}
3065
case ClassComponent: {
3075
);
3076
}
3077
3042
- recursivelyTraverseDisappearLayoutEffects(finishedWork);
3078
+ recursivelyTraverseDisappearLayoutEffects(
3079
+ finishedWork,
3080
+ layoutEffectTraversalFlags,
3081
+ );
3082
break;
3083
}
3084
case HostSingleton: {
3085
// $FlowFixMe[constant-condition]
3086
if (supportsSingletons) {
3048
- // TODO (Offscreen) Check: flags & RefStatic
3049
- commitHostSingletonRelease(finishedWork);
3087
+ const includeHostSingletons =
3088
+ (layoutEffectTraversalFlags & IncludeHostSingletons) !==
3089
+ NoLayoutEffectTraversalFlags;
3090
+ if (includeHostSingletons) {
3091
+ // TODO (Offscreen) Check: flags & RefStatic
3092
+ commitHostSingletonRelease(finishedWork);
3093
+ }
3094
}
3095
// Expected fallthrough to HostComponent
3096
}
3107
commitFragmentInstanceDeletionEffects(finishedWork);
3108
}
3109
3066
- recursivelyTraverseDisappearLayoutEffects(finishedWork);
3110
+ recursivelyTraverseDisappearLayoutEffects(
3111
+ finishedWork,
3112
+ layoutEffectTraversalFlags,
3113
+ );
3114
break;
3115
}
3116
case OffscreenComponent: {
3119
// Nested Offscreen tree is already hidden. Don't disappear
3120
// its effects.
3121
} else {
3075
- recursivelyTraverseDisappearLayoutEffects(finishedWork);
3122
+ recursivelyTraverseDisappearLayoutEffects(
3123
+ finishedWork,
3124
+ layoutEffectTraversalFlags,
3125
+ );
3126
}
3127
break;
3128
}
3135
}
3136
safelyDetachRef(finishedWork, finishedWork.return);
3137
}
3088
- recursivelyTraverseDisappearLayoutEffects(finishedWork);
3138
+ recursivelyTraverseDisappearLayoutEffects(
3139
+ finishedWork,
3140
+ layoutEffectTraversalFlags,
3141
+ );
3142
break;
3143
}
3144
case Fragment: {
3148
// Fallthrough
3149
}
3150
default: {
3098
- recursivelyTraverseDisappearLayoutEffects(finishedWork);
3151
+ recursivelyTraverseDisappearLayoutEffects(
3152
+ finishedWork,
3153
+ layoutEffectTraversalFlags,
3154
+ );
3155
break;
3156
}
3157
}
3180
popComponentEffectDidSpawnUpdate(prevEffectDidSpawnUpdate);
3181
}
3182
3127
-function recursivelyTraverseDisappearLayoutEffects(parentFiber: Fiber) {
3183
+function recursivelyTraverseDisappearLayoutEffects(
3184
+ parentFiber: Fiber,
3185
+ layoutEffectTraversalFlags: LayoutEffectTraversalFlags,
3186
+) {
3187
// TODO (Offscreen) Check: subtreeflags & (RefStatic | LayoutStatic)
3188
let child = parentFiber.child;
3189
while (child !== null) {
3131
- disappearLayoutEffects(child);
3190
+ disappearLayoutEffects(child, layoutEffectTraversalFlags);
3191
child = child.sibling;
3192
}
3193
}
3194
3136
-export function reappearLayoutEffects(
3195
+export function reappearLayoutEffectsForDEVValidation(
3196
+ finishedRoot: FiberRoot,
3197
+ current: Fiber | null,
3198
+ finishedWork: Fiber,
3199
+) {
3200
+ if (__DEV__) {
3201
+ reappearLayoutEffects(
3202
+ finishedRoot,
3203
+ current,
3204
+ finishedWork,
3205
+ NoLayoutEffectTraversalFlags,
3206
+ );
3207
+ }
3208
+}
3209
+
3210
+function reappearLayoutEffects(
3211
finishedRoot: FiberRoot,
3212
current: Fiber | null,
3213
finishedWork: Fiber,
3214
// This function visits both newly finished work and nodes that were re-used
3215
// from a previously committed tree. We cannot check non-static flags if the
3216
// node was reused.
3143
- includeWorkInProgressEffects: boolean,
3217
+ layoutEffectTraversalFlags: LayoutEffectTraversalFlags,
3218
) {
3219
const prevEffectStart = pushComponentEffectStart();
3220
const prevEffectDuration = pushComponentEffectDuration();
3222
const prevEffectDidSpawnUpdate = pushComponentEffectDidSpawnUpdate();
3223
// Turn on layout effects in a tree that previously disappeared.
3224
const flags = finishedWork.flags;
3225
+ const includeWorkInProgressEffects =
3226
+ (layoutEffectTraversalFlags & IncludeWorkInProgressEffects) !==
3227
+ NoLayoutEffectTraversalFlags;
3228
switch (finishedWork.tag) {
3229
case FunctionComponent:
3230
case ForwardRef:
3232
recursivelyTraverseReappearLayoutEffects(
3233
finishedRoot,
3234
finishedWork,
3158
- includeWorkInProgressEffects,
3235
+ layoutEffectTraversalFlags,
3236
);
3237
// TODO: Check flags & LayoutStatic
3238
commitHookLayoutEffects(finishedWork, HookLayout);
3242
recursivelyTraverseReappearLayoutEffects(
3243
finishedRoot,
3244
finishedWork,
3168
- includeWorkInProgressEffects,
3245
+ layoutEffectTraversalFlags,
3246
);
3247
3248
commitClassDidMount(finishedWork);
3267
case HostSingleton: {
3268
// $FlowFixMe[constant-condition]
3269
if (supportsSingletons) {
3193
- // We acquire the singleton instance first so it has appropriate
3194
- // styles before other layout effects run. This isn't perfect because
3195
- // an early sibling of the singleton may have an effect that can
3196
- // observe the singleton before it is acquired.
3197
- // @TODO move this to the mutation phase. The reason it isn't there yet
3198
- // is it seemingly requires an extra traversal because we need to move the
3199
- // disappear effect into a phase before the appear phase
3200
- commitHostSingletonAcquisition(finishedWork);
3201
- // We fall through to the HostComponent case below.
3270
+ const includeHostSingletons =
3271
+ (layoutEffectTraversalFlags & IncludeHostSingletons) !==
3272
+ NoLayoutEffectTraversalFlags;
3273
+ if (includeHostSingletons) {
3274
+ // We acquire the singleton instance first so it has appropriate
3275
+ // styles before other layout effects run. This isn't perfect because
3276
+ // an early sibling of the singleton may have an effect that can
3277
+ // observe the singleton before it is acquired.
3278
+ // @TODO move this to the mutation phase. The reason it isn't there yet
3279
+ // is it seemingly requires an extra traversal because we need to move the
3280
+ // disappear effect into a phase before the appear phase
3281
+ commitHostSingletonAcquisition(finishedWork);
3282
+ // We fall through to the HostComponent case below.
3283
+ }
3284
}
3285
// Fallthrough
3286
}
3293
recursivelyTraverseReappearLayoutEffects(
3294
finishedRoot,
3295
finishedWork,
3214
- includeWorkInProgressEffects,
3296
+ layoutEffectTraversalFlags,
3297
);
3298
3299
// Renderers may schedule work to be done after host components are mounted
3316
recursivelyTraverseReappearLayoutEffects(
3317
finishedRoot,
3318
finishedWork,
3237
- includeWorkInProgressEffects,
3319
+ layoutEffectTraversalFlags,
3320
);
3321
3322
const profilerInstance = finishedWork.stateNode;
3339
recursivelyTraverseReappearLayoutEffects(
3340
finishedRoot,
3341
finishedWork,
3260
- includeWorkInProgressEffects,
3342
+ layoutEffectTraversalFlags,
3343
);
3344
}
3345
break;
3348
recursivelyTraverseReappearLayoutEffects(
3349
finishedRoot,
3350
finishedWork,
3269
- includeWorkInProgressEffects,
3351
+ layoutEffectTraversalFlags,
3352
);
3353
3354
if (includeWorkInProgressEffects && flags & Update) {
3361
recursivelyTraverseReappearLayoutEffects(
3362
finishedRoot,
3363
finishedWork,
3282
- includeWorkInProgressEffects,
3364
+ layoutEffectTraversalFlags,
3365
);
3366
3367
if (includeWorkInProgressEffects && flags & Update) {
3380
recursivelyTraverseReappearLayoutEffects(
3381
finishedRoot,
3382
finishedWork,
3301
- includeWorkInProgressEffects,
3383
+ layoutEffectTraversalFlags,
3384
);
3385
}
3386
// TODO: Check flags & Ref
3392
recursivelyTraverseReappearLayoutEffects(
3393
finishedRoot,
3394
finishedWork,
3313
- includeWorkInProgressEffects,
3395
+ layoutEffectTraversalFlags,
3396
);
3397
if (__DEV__) {
3398
if (flags & ViewTransitionNamedStatic) {
3414
recursivelyTraverseReappearLayoutEffects(
3415
finishedRoot,
3416
finishedWork,
3335
- includeWorkInProgressEffects,
3417
+ layoutEffectTraversalFlags,
3418
);
3419
break;
3420
}
3447
function recursivelyTraverseReappearLayoutEffects(
3448
finishedRoot: FiberRoot,
3449
parentFiber: Fiber,
3368
- includeWorkInProgressEffects: boolean,
3450
+ layoutEffectTraversalFlags: LayoutEffectTraversalFlags,
3451
) {
3452
// This function visits both newly finished work and nodes that were re-used
3453
// from a previously committed tree. We cannot check non-static flags if the
3454
// node was reused.
3373
- const childShouldIncludeWorkInProgressEffects =
3374
- includeWorkInProgressEffects &&
3375
- (parentFiber.subtreeFlags & LayoutMask) !== NoFlags;
3455
+ const childLayoutEffectTraversalFlags =
3456
+ (parentFiber.subtreeFlags & LayoutMask) !== NoFlags
3457
+ ? layoutEffectTraversalFlags
3458
+ : layoutEffectTraversalFlags & ~IncludeWorkInProgressEffects;
3459
3460
// TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic)
3461
let child = parentFiber.child;
3465
finishedRoot,
3466
current,
3467
child,
3385
- childShouldIncludeWorkInProgressEffects,
3468
+ childLayoutEffectTraversalFlags,
3469
);
3470
child = child.sibling;
3471
}