@@ -22,6 +22,7 @@ import type {CapturedValue, CapturedError} from './ReactCapturedValue';
22
22
import type { SuspenseState } from './ReactFiberSuspenseComponent' ;
23
23
import type { FunctionComponentUpdateQueue } from './ReactFiberHooks' ;
24
24
import type { Thenable } from './ReactFiberWorkLoop' ;
25
+ import type { ReactPriorityLevel } from './SchedulerWithReactIntegration' ;
25
26
26
27
import { unstable_wrap as Schedule_tracing_wrap } from 'scheduler/tracing' ;
27
28
import {
@@ -116,6 +117,7 @@ import {
116
117
MountPassive ,
117
118
} from './ReactHookEffectTags' ;
118
119
import { didWarnAboutReassigningProps } from './ReactFiberBeginWork' ;
120
+ import { runWithPriority , NormalPriority } from './SchedulerWithReactIntegration' ;
119
121
120
122
let didWarnAboutUndefinedSnapshotBeforeUpdate : Set < mixed > | null = null ;
121
123
if ( __DEV__ ) {
@@ -716,7 +718,10 @@ function commitDetachRef(current: Fiber) {
716
718
// User-originating errors (lifecycles and refs) should not interrupt
717
719
// deletion, so don't let them throw. Host-originating errors should
718
720
// interrupt deletion, so it's okay
719
- function commitUnmount ( current : Fiber ) : void {
721
+ function commitUnmount (
722
+ current : Fiber ,
723
+ renderPriorityLevel : ReactPriorityLevel ,
724
+ ) : void {
720
725
onCommitUnmount ( current ) ;
721
726
722
727
switch ( current . tag ) {
@@ -729,14 +734,33 @@ function commitUnmount(current: Fiber): void {
729
734
const lastEffect = updateQueue . lastEffect ;
730
735
if ( lastEffect !== null ) {
731
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
+ } ) ;
740
764
}
741
765
}
742
766
break ;
@@ -777,7 +801,7 @@ function commitUnmount(current: Fiber): void {
777
801
// We are also not using this parent because
778
802
// the portal will get pushed immediately.
779
803
if ( supportsMutation ) {
780
- unmountHostComponents ( current ) ;
804
+ unmountHostComponents ( current , renderPriorityLevel ) ;
781
805
} else if ( supportsPersistence ) {
782
806
emptyPortalContainer ( current ) ;
783
807
}
@@ -795,15 +819,18 @@ function commitUnmount(current: Fiber): void {
795
819
}
796
820
}
797
821
798
- function commitNestedUnmounts ( root : Fiber ) : void {
822
+ function commitNestedUnmounts (
823
+ root : Fiber ,
824
+ renderPriorityLevel : ReactPriorityLevel ,
825
+ ) : void {
799
826
// While we're inside a removed host node we don't want to call
800
827
// removeChild on the inner nodes because they're removed by the top
801
828
// call anyway. We also want to call componentWillUnmount on all
802
829
// composites before this host node is removed from the tree. Therefore
803
830
// we do an inner loop while we're still inside the host node.
804
831
let node : Fiber = root ;
805
832
while ( true ) {
806
- commitUnmount ( node ) ;
833
+ commitUnmount ( node , renderPriorityLevel ) ;
807
834
// Visit children because they may contain more composite or host nodes.
808
835
// Skip portals because commitUnmount() currently visits them recursively.
809
836
if (
@@ -1054,7 +1081,7 @@ function commitPlacement(finishedWork: Fiber): void {
1054
1081
}
1055
1082
}
1056
1083
1057
- function unmountHostComponents ( current ) : void {
1084
+ function unmountHostComponents ( current , renderPriorityLevel ) : void {
1058
1085
// We only have the top Fiber that was deleted but we need to recurse down its
1059
1086
// children to find all the terminal nodes.
1060
1087
let node : Fiber = current ;
@@ -1102,7 +1129,7 @@ function unmountHostComponents(current): void {
1102
1129
}
1103
1130
1104
1131
if ( node . tag === HostComponent || node . tag === HostText ) {
1105
- commitNestedUnmounts ( node ) ;
1132
+ commitNestedUnmounts ( node , renderPriorityLevel ) ;
1106
1133
// After all the children have unmounted, it is now safe to remove the
1107
1134
// node from the tree.
1108
1135
if ( currentParentIsContainer ) {
@@ -1119,7 +1146,7 @@ function unmountHostComponents(current): void {
1119
1146
// Don't visit children because we already visited them.
1120
1147
} else if ( node . tag === FundamentalComponent ) {
1121
1148
const fundamentalNode = node . stateNode . instance ;
1122
- commitNestedUnmounts ( node ) ;
1149
+ commitNestedUnmounts ( node , renderPriorityLevel ) ;
1123
1150
// After all the children have unmounted, it is now safe to remove the
1124
1151
// node from the tree.
1125
1152
if ( currentParentIsContainer ) {
@@ -1161,7 +1188,7 @@ function unmountHostComponents(current): void {
1161
1188
continue ;
1162
1189
}
1163
1190
} else {
1164
- commitUnmount ( node ) ;
1191
+ commitUnmount ( node , renderPriorityLevel ) ;
1165
1192
// Visit children because we may find more host components below.
1166
1193
if ( node . child !== null ) {
1167
1194
node . child . return = node ;
@@ -1188,14 +1215,17 @@ function unmountHostComponents(current): void {
1188
1215
}
1189
1216
}
1190
1217
1191
- function commitDeletion ( current : Fiber ) : void {
1218
+ function commitDeletion (
1219
+ current : Fiber ,
1220
+ renderPriorityLevel : ReactPriorityLevel ,
1221
+ ) : void {
1192
1222
if ( supportsMutation ) {
1193
1223
// Recursively delete all host nodes from the parent.
1194
1224
// Detach refs and call componentWillUnmount() on the whole subtree.
1195
- unmountHostComponents ( current ) ;
1225
+ unmountHostComponents ( current , renderPriorityLevel ) ;
1196
1226
} else {
1197
1227
// Detach refs and call componentWillUnmount() on the whole subtree.
1198
- commitNestedUnmounts ( current ) ;
1228
+ commitNestedUnmounts ( current , renderPriorityLevel ) ;
1199
1229
}
1200
1230
detachFiber ( current ) ;
1201
1231
}
0 commit comments