@@ -212,6 +212,7 @@ import {
212
212
commitResetTextContent ,
213
213
isSuspenseBoundaryBeingHidden ,
214
214
safelyCallDestroy ,
215
+ safelyCallDestroyForUnmountedFiber ,
215
216
} from './ReactFiberCommitWork.new' ;
216
217
import { enqueueUpdate } from './ReactUpdateQueue.new' ;
217
218
import { resetContextDependencies } from './ReactFiberNewContext.new' ;
@@ -2847,7 +2848,7 @@ function flushPassiveUnmountEffects(firstChild: Fiber): void {
2847
2848
if ( deletions !== null ) {
2848
2849
for ( let i = 0 ; i < deletions . length ; i ++ ) {
2849
2850
const fiberToDelete = deletions [ i ] ;
2850
- flushPassiveUnmountEffectsInsideOfDeletedTree ( fiberToDelete ) ;
2851
+ flushPassiveUnmountEffectsForUnmountedFiber ( fiberToDelete , fiber ) ;
2851
2852
2852
2853
// Now that passive effects have been processed, it's safe to detach lingering pointers.
2853
2854
detachFiberAfterEffects ( fiberToDelete ) ;
@@ -2882,8 +2883,9 @@ function flushPassiveUnmountEffects(firstChild: Fiber): void {
2882
2883
}
2883
2884
}
2884
2885
2885
- function flushPassiveUnmountEffectsInsideOfDeletedTree (
2886
+ function flushPassiveUnmountEffectsForUnmountedFiber (
2886
2887
fiberToDelete : Fiber ,
2888
+ nearestMountedAncestor : Fiber ,
2887
2889
) : void {
2888
2890
if ( ( fiberToDelete . subtreeTag & PassiveStaticSubtreeTag ) !== NoSubtreeTag ) {
2889
2891
// If any children have passive effects then traverse the subtree.
@@ -2892,7 +2894,10 @@ function flushPassiveUnmountEffectsInsideOfDeletedTree(
2892
2894
// since that would not cover passive effects in siblings.
2893
2895
let child = fiberToDelete . child ;
2894
2896
while ( child !== null ) {
2895
- flushPassiveUnmountEffectsInsideOfDeletedTree ( child ) ;
2897
+ flushPassiveUnmountEffectsForUnmountedFiber (
2898
+ child ,
2899
+ nearestMountedAncestor ,
2900
+ ) ;
2896
2901
child = child . sibling ;
2897
2902
}
2898
2903
}
@@ -2903,16 +2908,64 @@ function flushPassiveUnmountEffectsInsideOfDeletedTree(
2903
2908
case ForwardRef :
2904
2909
case SimpleMemoComponent :
2905
2910
case Block : {
2906
- flushPassiveUnmountEffectsImpl ( fiberToDelete , HookPassive ) ;
2911
+ flushPassiveUnmountEffectsForUnmountedFiberImpl (
2912
+ fiberToDelete ,
2913
+ nearestMountedAncestor ,
2914
+ ) ;
2907
2915
}
2908
2916
}
2909
2917
}
2910
2918
}
2911
2919
2920
+ function flushPassiveUnmountEffectsForUnmountedFiberImpl (
2921
+ fiber : Fiber ,
2922
+ nearestMountedAncestor : Fiber ,
2923
+ ) : void {
2924
+ const updateQueue : FunctionComponentUpdateQueue | null = ( fiber . updateQueue : any ) ;
2925
+ const lastEffect = updateQueue !== null ? updateQueue . lastEffect : null ;
2926
+ if ( lastEffect !== null ) {
2927
+ setCurrentDebugFiberInDEV ( fiber ) ;
2928
+
2929
+ const firstEffect = lastEffect . next ;
2930
+ let effect = firstEffect ;
2931
+ do {
2932
+ const { next , tag } = effect ;
2933
+ if ( ( tag & HookPassive ) === HookPassive ) {
2934
+ const destroy = effect . destroy ;
2935
+ if ( destroy !== undefined ) {
2936
+ effect . destroy = undefined ;
2937
+
2938
+ if (
2939
+ enableProfilerTimer &&
2940
+ enableProfilerCommitHooks &&
2941
+ fiber . mode & ProfileMode
2942
+ ) {
2943
+ startPassiveEffectTimer ( ) ;
2944
+ safelyCallDestroyForUnmountedFiber (
2945
+ fiber ,
2946
+ nearestMountedAncestor ,
2947
+ destroy ,
2948
+ ) ;
2949
+ recordPassiveEffectDuration ( fiber ) ;
2950
+ } else {
2951
+ safelyCallDestroyForUnmountedFiber (
2952
+ fiber ,
2953
+ nearestMountedAncestor ,
2954
+ destroy ,
2955
+ ) ;
2956
+ }
2957
+ }
2958
+ }
2959
+ effect = next ;
2960
+ } while ( effect !== firstEffect ) ;
2961
+
2962
+ resetCurrentDebugFiberInDEV ( ) ;
2963
+ }
2964
+ }
2965
+
2912
2966
function flushPassiveUnmountEffectsImpl (
2913
2967
fiber : Fiber ,
2914
- // Tags to check for when deciding whether to unmount. e.g. to skip over
2915
- // layout effects
2968
+ // Tags to check for when deciding whether to unmount. e.g. to skip over layout effects
2916
2969
hookEffectTag : HookEffectTag ,
2917
2970
) : void {
2918
2971
const updateQueue : FunctionComponentUpdateQueue | null = ( fiber . updateQueue : any ) ;
@@ -3112,6 +3165,45 @@ export function captureCommitPhaseError(sourceFiber: Fiber, error: mixed) {
3112
3165
}
3113
3166
}
3114
3167
3168
+ export function captureCommitPhaseErrorForUnmountedFiber (
3169
+ sourceFiber : Fiber ,
3170
+ nearestMountedAncestor : Fiber ,
3171
+ error : mixed ,
3172
+ ) {
3173
+ let fiber = nearestMountedAncestor . return ;
3174
+ while ( fiber !== null ) {
3175
+ if ( fiber . tag === HostRoot ) {
3176
+ captureCommitPhaseErrorOnRoot ( fiber , sourceFiber , error ) ;
3177
+ return ;
3178
+ } else if ( fiber . tag === ClassComponent ) {
3179
+ const ctor = fiber . type ;
3180
+ const instance = fiber . stateNode ;
3181
+ if (
3182
+ typeof ctor . getDerivedStateFromError === 'function' ||
3183
+ ( typeof instance . componentDidCatch === 'function' &&
3184
+ ! isAlreadyFailedLegacyErrorBoundary ( instance ) )
3185
+ ) {
3186
+ const errorInfo = createCapturedValue ( error , sourceFiber ) ;
3187
+ const update = createClassErrorUpdate (
3188
+ fiber ,
3189
+ errorInfo ,
3190
+ ( SyncLane : Lane ) ,
3191
+ ) ;
3192
+ enqueueUpdate ( fiber , update ) ;
3193
+ const eventTime = requestEventTime ( ) ;
3194
+ const root = markUpdateLaneFromFiberToRoot ( fiber , ( SyncLane : Lane ) ) ;
3195
+ if ( root !== null ) {
3196
+ markRootUpdated ( root , SyncLane , eventTime ) ;
3197
+ ensureRootIsScheduled ( root , eventTime ) ;
3198
+ schedulePendingInteractions ( root , SyncLane ) ;
3199
+ }
3200
+ return ;
3201
+ }
3202
+ }
3203
+ fiber = fiber . return ;
3204
+ }
3205
+ }
3206
+
3115
3207
export function pingSuspendedRoot (
3116
3208
root : FiberRoot ,
3117
3209
wakeable : Wakeable ,
0 commit comments