43
} from './ReactFiberMutationTracking';
44
import {
45
MutationMask,
46
+ Placement,
47
Update,
48
ContentReset,
49
NoFlags,
53
AffectedParentLayout,
54
} from './ReactFiberFlags';
55
import {
56
+ HasEffect as HookHasEffect,
57
+ Insertion as HookInsertion,
58
+} from './ReactHookEffectTags';
59
+import {
60
+ FunctionComponent,
61
+ ForwardRef,
62
+ MemoComponent,
63
+ SimpleMemoComponent,
64
HostComponent,
65
HostHoistable,
66
HostSingleton,
81
pushViewTransitionCancelableScope,
82
popViewTransitionCancelableScope,
83
} from './ReactFiberCommitViewTransitions';
84
+import {
85
+ commitHookEffectListMount,
86
+ commitHookEffectListUnmount,
87
+} from './ReactFiberCommitEffects';
88
import {
89
getViewTransitionName,
90
getViewTransitionClassName,
391
if (
392
visitPhase === INSERT_APPEARING_PAIR &&
393
parentViewTransition === null &&
381
- (parentFiber.subtreeFlags & ViewTransitionNamedStatic) === NoFlags
394
+ (parentFiber.subtreeFlags & (ViewTransitionNamedStatic | Placement)) ===
395
+ NoFlags
396
) {
383
- // We're just searching for pairs but we have reached the end.
397
+ // We're just searching for pairs or insertion effects but we have reached the end.
398
return;
399
}
400
let child = parentFiber.child;
416
visitPhase: VisitPhase,
417
): void {
418
switch (finishedWork.tag) {
419
+ case FunctionComponent:
420
+ case ForwardRef:
421
+ case MemoComponent:
422
+ case SimpleMemoComponent: {
423
+ recursivelyInsertNew(
424
+ finishedWork,
425
+ hostParentClone,
426
+ parentViewTransition,
427
+ visitPhase,
428
+ );
429
+ if (finishedWork.flags & Update) {
430
+ // Insertion Effects are mounted temporarily during the rendering of the snapshot.
431
+ // This does not affect cloned Offscreen content since those would've been mounted
432
+ // while inside the offscreen tree already.
433
+ // Note that because we are mounting a clone of the DOM tree and the previous DOM
434
+ // tree remains mounted during the snapshot, we can't unmount any previous insertion
435
+ // effects. This can lead to conflicts but that is similar to what can happen with
436
+ // conflicts for two mounted Activity boundaries.
437
+ commitHookEffectListMount(HookInsertion | HookHasEffect, finishedWork);
438
+ }
439
+ break;
440
+ }
441
case HostHoistable: {
442
if (supportsResources) {
443
// TODO: Hoistables should get optimistically inserted and then removed.
1075
}
1076
}
1077
1078
+function recursivelyRestoreNew(
1079
+ finishedWork: Fiber,
1080
+ nearestMountedAncestor: Fiber,
1081
+): void {
1082
+ // There has to be move a Placement AND an Update flag somewhere below for this
1083
+ // pass to be relevant since we only apply insertion effects for new components here.
1084
+ if (((Placement | Update) & finishedWork.subtreeFlags) !== NoFlags) {
1085
+ let child = finishedWork.child;
1086
+ while (child !== null) {
1087
+ recursivelyRestoreNew(child, nearestMountedAncestor);
1088
+ child = child.sibling;
1089
+ }
1090
+ }
1091
+ switch (finishedWork.tag) {
1092
+ case FunctionComponent:
1093
+ case ForwardRef:
1094
+ case MemoComponent:
1095
+ case SimpleMemoComponent: {
1096
+ const current = finishedWork.alternate;
1097
+ if (current === null && finishedWork.flags & Update) {
1098
+ // Insertion Effects are mounted temporarily during the rendering of the snapshot.
1099
+ // We have now already takes a snapshot of the inserted state so we can now unmount
1100
+ // them to get back into the original state before starting the animation.
1101
+ commitHookEffectListUnmount(
1102
+ HookInsertion | HookHasEffect,
1103
+ finishedWork,
1104
+ nearestMountedAncestor,
1105
+ );
1106
+ }
1107
+ break;
1108
+ }
1109
+ }
1110
+}
1111
+
1112
function recursivelyApplyViewTransitions(parentFiber: Fiber) {
1113
const deletions = parentFiber.deletions;
1114
if (deletions !== null) {
1125
// If we have mutations or if this is a newly inserted tree, clone as we go.
1126
let child = parentFiber.child;
1127
while (child !== null) {
1058
- applyViewTransitionsOnFiber(child);
1128
+ const current = child.alternate;
1129
+ if (current === null) {
1130
+ measureExitViewTransitions(child);
1131
+ recursivelyRestoreNew(child, parentFiber);
1132
+ } else {
1133
+ applyViewTransitionsOnFiber(child, current);
1134
+ }
1135
child = child.sibling;
1136
}
1137
} else {
1142
}
1143
}
1144
1069
-function applyViewTransitionsOnFiber(finishedWork: Fiber) {
1070
- const current = finishedWork.alternate;
1071
- if (current === null) {
1072
- measureExitViewTransitions(finishedWork);
1073
- return;
1074
- }
1075
-
1076
- const flags = finishedWork.flags;
1145
+function applyViewTransitionsOnFiber(finishedWork: Fiber, current: Fiber) {
1146
// The effect flag should be checked *after* we refine the type of fiber,
1147
// because the fiber tag is more specific. An exception is any flag related
1148
// to reconciliation, because those can be set on all fiber types.
1152
break;
1153
}
1154
case OffscreenComponent: {
1086
- if (flags & Visibility) {
1087
- const newState: OffscreenState | null = finishedWork.memoizedState;
1088
- const isHidden = newState !== null;
1089
- if (!isHidden) {
1155
+ const newState: OffscreenState | null = finishedWork.memoizedState;
1156
+ const isHidden = newState !== null;
1157
+ const wasHidden = current.memoizedState !== null;
1158
+ if (!isHidden) {
1159
+ if (wasHidden) {
1160
measureExitViewTransitions(finishedWork);
1091
- } else if (current !== null && current.memoizedState === null) {
1161
+ recursivelyRestoreNew(finishedWork, finishedWork);
1162
+ } else {
1163
+ recursivelyApplyViewTransitions(finishedWork);
1164
+ }
1165
+ } else {
1166
+ if (!wasHidden) {
1167
// Was previously mounted as visible but is now hidden.
1168
commitEnterViewTransitions(current, true);
1169
}