22
import type {SuspenseState} from './ReactFiberSuspenseComponent';
23
import type {FunctionComponentUpdateQueue} from './ReactFiberHooks';
24
import type {Thenable} from './ReactFiberWorkLoop';
25
+import type {ReactPriorityLevel} from './SchedulerWithReactIntegration';
26
27
import {unstable_wrap as Schedule_tracing_wrap} from 'scheduler/tracing';
28
import {
117
MountPassive,
118
} from './ReactHookEffectTags';
119
import {didWarnAboutReassigningProps} from './ReactFiberBeginWork';
120
+import {runWithPriority, NormalPriority} from './SchedulerWithReactIntegration';
121
122
let didWarnAboutUndefinedSnapshotBeforeUpdate: Set<mixed> | null = null;
123
if (__DEV__) {
718
// User-originating errors (lifecycles and refs) should not interrupt
719
// deletion, so don't let them throw. Host-originating errors should
720
// interrupt deletion, so it's okay
719
-function commitUnmount(current: Fiber): void {
721
+function commitUnmount(
722
+ current: Fiber,
723
+ renderPriorityLevel: ReactPriorityLevel,
724
+): void {
725
onCommitUnmount(current);
726
727
switch (current.tag) {
734
const lastEffect = updateQueue.lastEffect;
735
if (lastEffect !== null) {
736
const firstEffect = lastEffect.next;
732
- let effect = firstEffect;
733
- do {
734
- const destroy = effect.destroy;
735
- if (destroy !== undefined) {
736
- safelyCallDestroy(current, destroy);
737
- }
738
- effect = effect.next;
739
- } while (effect !== firstEffect);
737
+
738
+ // When the owner fiber is deleted, the destroy function of a passive
739
+ // effect hook is called during the synchronous commit phase. This is
740
+ // a concession to implementation complexity. Calling it in the
741
+ // passive effect phase (like they usually are, when dependencies
742
+ // change during an update) would require either traversing the
743
+ // children of the deleted fiber again, or including unmount effects
744
+ // as part of the fiber effect list.
745
+ //
746
+ // Because this is during the sync commit phase, we need to change
747
+ // the priority.
748
+ //
749
+ // TODO: Reconsider this implementation trade off.
750
+ const priorityLevel =
751
+ renderPriorityLevel > NormalPriority
752
+ ? NormalPriority
753
+ : renderPriorityLevel;
754
+ runWithPriority(priorityLevel, () => {
755
+ let effect = firstEffect;
756
+ do {
757
+ const destroy = effect.destroy;
758
+ if (destroy !== undefined) {
759
+ safelyCallDestroy(current, destroy);
760
+ }
761
+ effect = effect.next;
762
+ } while (effect !== firstEffect);
763
+ });
764
}
765
}
766
break;
801
// We are also not using this parent because
802
// the portal will get pushed immediately.
803
if (supportsMutation) {
780
- unmountHostComponents(current);
804
+ unmountHostComponents(current, renderPriorityLevel);
805
} else if (supportsPersistence) {
806
emptyPortalContainer(current);
807
}
819
}
820
}
821
798
-function commitNestedUnmounts(root: Fiber): void {
822
+function commitNestedUnmounts(
823
+ root: Fiber,
824
+ renderPriorityLevel: ReactPriorityLevel,
825
+): void {
826
// While we're inside a removed host node we don't want to call
827
// removeChild on the inner nodes because they're removed by the top
828
// call anyway. We also want to call componentWillUnmount on all
830
// we do an inner loop while we're still inside the host node.
831
let node: Fiber = root;
832
while (true) {
806
- commitUnmount(node);
833
+ commitUnmount(node, renderPriorityLevel);
834
// Visit children because they may contain more composite or host nodes.
835
// Skip portals because commitUnmount() currently visits them recursively.
836
if (
1081
}
1082
}
1083
1057
-function unmountHostComponents(current): void {
1084
+function unmountHostComponents(current, renderPriorityLevel): void {
1085
// We only have the top Fiber that was deleted but we need to recurse down its
1086
// children to find all the terminal nodes.
1087
let node: Fiber = current;
1129
}
1130
1131
if (node.tag === HostComponent || node.tag === HostText) {
1105
- commitNestedUnmounts(node);
1132
+ commitNestedUnmounts(node, renderPriorityLevel);
1133
// After all the children have unmounted, it is now safe to remove the
1134
// node from the tree.
1135
if (currentParentIsContainer) {
1146
// Don't visit children because we already visited them.
1147
} else if (node.tag === FundamentalComponent) {
1148
const fundamentalNode = node.stateNode.instance;
1122
- commitNestedUnmounts(node);
1149
+ commitNestedUnmounts(node, renderPriorityLevel);
1150
// After all the children have unmounted, it is now safe to remove the
1151
// node from the tree.
1152
if (currentParentIsContainer) {
1188
continue;
1189
}
1190
} else {
1164
- commitUnmount(node);
1191
+ commitUnmount(node, renderPriorityLevel);
1192
// Visit children because we may find more host components below.
1193
if (node.child !== null) {
1194
node.child.return = node;
1215
}
1216
}
1217
1191
-function commitDeletion(current: Fiber): void {
1218
+function commitDeletion(
1219
+ current: Fiber,
1220
+ renderPriorityLevel: ReactPriorityLevel,
1221
+): void {
1222
if (supportsMutation) {
1223
// Recursively delete all host nodes from the parent.
1224
// Detach refs and call componentWillUnmount() on the whole subtree.
1195
- unmountHostComponents(current);
1225
+ unmountHostComponents(current, renderPriorityLevel);
1226
} else {
1227
// Detach refs and call componentWillUnmount() on the whole subtree.
1198
- commitNestedUnmounts(current);
1228
+ commitNestedUnmounts(current, renderPriorityLevel);
1229
}
1230
detachFiber(current);
1231
}