@@ -212,6 +212,7 @@ import {
212212 commitResetTextContent ,
213213 isSuspenseBoundaryBeingHidden ,
214214 safelyCallDestroy ,
215+ safelyCallDestroyForUnmountedFiber ,
215216} from './ReactFiberCommitWork.new' ;
216217import { enqueueUpdate } from './ReactUpdateQueue.new' ;
217218import { resetContextDependencies } from './ReactFiberNewContext.new' ;
@@ -2847,7 +2848,7 @@ function flushPassiveUnmountEffects(firstChild: Fiber): void {
28472848 if ( deletions !== null ) {
28482849 for ( let i = 0 ; i < deletions . length ; i ++ ) {
28492850 const fiberToDelete = deletions [ i ] ;
2850- flushPassiveUnmountEffectsInsideOfDeletedTree ( fiberToDelete ) ;
2851+ flushPassiveUnmountEffectsForUnmountedFiber ( fiberToDelete , fiber ) ;
28512852
28522853 // Now that passive effects have been processed, it's safe to detach lingering pointers.
28532854 detachFiberAfterEffects ( fiberToDelete ) ;
@@ -2882,8 +2883,9 @@ function flushPassiveUnmountEffects(firstChild: Fiber): void {
28822883 }
28832884}
28842885
2885- function flushPassiveUnmountEffectsInsideOfDeletedTree (
2886+ function flushPassiveUnmountEffectsForUnmountedFiber (
28862887 fiberToDelete : Fiber ,
2888+ nearestMountedAncestor : Fiber ,
28872889) : void {
28882890 if ( ( fiberToDelete . subtreeTag & PassiveStaticSubtreeTag ) !== NoSubtreeTag ) {
28892891 // If any children have passive effects then traverse the subtree.
@@ -2892,7 +2894,10 @@ function flushPassiveUnmountEffectsInsideOfDeletedTree(
28922894 // since that would not cover passive effects in siblings.
28932895 let child = fiberToDelete . child ;
28942896 while ( child !== null ) {
2895- flushPassiveUnmountEffectsInsideOfDeletedTree ( child ) ;
2897+ flushPassiveUnmountEffectsForUnmountedFiber (
2898+ child ,
2899+ nearestMountedAncestor ,
2900+ ) ;
28962901 child = child . sibling ;
28972902 }
28982903 }
@@ -2903,16 +2908,64 @@ function flushPassiveUnmountEffectsInsideOfDeletedTree(
29032908 case ForwardRef :
29042909 case SimpleMemoComponent :
29052910 case Block : {
2906- flushPassiveUnmountEffectsImpl ( fiberToDelete , HookPassive ) ;
2911+ flushPassiveUnmountEffectsForUnmountedFiberImpl (
2912+ fiberToDelete ,
2913+ nearestMountedAncestor ,
2914+ ) ;
29072915 }
29082916 }
29092917 }
29102918}
29112919
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+
29122966function flushPassiveUnmountEffectsImpl (
29132967 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
29162969 hookEffectTag : HookEffectTag ,
29172970) : void {
29182971 const updateQueue : FunctionComponentUpdateQueue | null = ( fiber . updateQueue : any ) ;
@@ -3112,6 +3165,45 @@ export function captureCommitPhaseError(sourceFiber: Fiber, error: mixed) {
31123165 }
31133166}
31143167
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+
31153207export function pingSuspendedRoot (
31163208 root : FiberRoot ,
31173209 wakeable : Wakeable ,
0 commit comments