@@ -24,6 +24,7 @@ import type {FunctionComponentUpdateQueue} from './ReactFiberHooks.new';
24
24
import type { Wakeable } from 'shared/ReactTypes' ;
25
25
import type { ReactPriorityLevel } from './ReactInternalTypes' ;
26
26
import type { OffscreenState } from './ReactFiberOffscreenComponent' ;
27
+ import type { HookFlags } from './ReactHookEffectTags' ;
27
28
28
29
import { unstable_wrap as Schedule_tracing_wrap } from 'scheduler/tracing' ;
29
30
import {
@@ -65,10 +66,13 @@ import {
65
66
NoFlags ,
66
67
ContentReset ,
67
68
Placement ,
69
+ ChildDeletion ,
68
70
Snapshot ,
69
71
Update ,
70
72
Passive ,
73
+ PassiveStatic ,
71
74
PassiveMask ,
75
+ PassiveUnmountPendingDev ,
72
76
} from './ReactFiberFlags' ;
73
77
import getComponentName from 'shared/getComponentName' ;
74
78
import invariant from 'shared/invariant' ;
@@ -340,19 +344,19 @@ function commitBeforeMutationLifeCycles(
340
344
) ;
341
345
}
342
346
343
- function commitHookEffectListUnmount ( tag : number , finishedWork : Fiber ) {
347
+ function commitHookEffectListUnmount ( flags : HookFlags , finishedWork : Fiber ) {
344
348
const updateQueue : FunctionComponentUpdateQueue | null = ( finishedWork . updateQueue : any ) ;
345
349
const lastEffect = updateQueue !== null ? updateQueue . lastEffect : null ;
346
350
if ( lastEffect !== null ) {
347
351
const firstEffect = lastEffect . next ;
348
352
let effect = firstEffect ;
349
353
do {
350
- if ( ( effect . tag & tag ) === tag ) {
354
+ if ( ( effect . tag & flags ) === flags ) {
351
355
// Unmount
352
356
const destroy = effect . destroy ;
353
357
effect . destroy = undefined ;
354
358
if ( destroy !== undefined ) {
355
- destroy ( ) ;
359
+ safelyCallDestroy ( finishedWork , destroy ) ;
356
360
}
357
361
}
358
362
effect = effect . next ;
@@ -1914,6 +1918,154 @@ function commitPassiveMountOnFiber(
1914
1918
}
1915
1919
}
1916
1920
1921
+ export function commitPassiveUnmountEffects ( firstChild : Fiber ) : void {
1922
+ nextEffect = firstChild ;
1923
+ commitPassiveUnmountEffects_begin ( ) ;
1924
+ }
1925
+
1926
+ function commitPassiveUnmountEffects_begin ( ) {
1927
+ while ( nextEffect !== null ) {
1928
+ const fiber = nextEffect ;
1929
+ const child = fiber . child ;
1930
+
1931
+ if ( ( nextEffect . flags & ChildDeletion ) !== NoFlags ) {
1932
+ const deletions = fiber . deletions ;
1933
+ if ( deletions !== null ) {
1934
+ for ( let i = 0 ; i < deletions . length ; i ++ ) {
1935
+ const fiberToDelete = deletions [ i ] ;
1936
+ nextEffect = fiberToDelete ;
1937
+ commitPassiveUnmountEffectsInsideOfDeletedTree_begin ( fiberToDelete ) ;
1938
+
1939
+ // Now that passive effects have been processed, it's safe to detach lingering pointers.
1940
+ detachFiberAfterEffects ( fiberToDelete ) ;
1941
+ }
1942
+ nextEffect = fiber ;
1943
+ }
1944
+ }
1945
+
1946
+ if ( ( fiber . subtreeFlags & PassiveMask ) !== NoFlags && child !== null ) {
1947
+ ensureCorrectReturnPointer ( child , fiber ) ;
1948
+ nextEffect = child ;
1949
+ } else {
1950
+ commitPassiveUnmountEffects_complete ( ) ;
1951
+ }
1952
+ }
1953
+ }
1954
+
1955
+ function commitPassiveUnmountEffects_complete ( ) {
1956
+ while ( nextEffect !== null ) {
1957
+ const fiber = nextEffect ;
1958
+ if ( ( fiber . flags & Passive ) !== NoFlags ) {
1959
+ setCurrentDebugFiberInDEV ( fiber ) ;
1960
+ commitPassiveUnmountOnFiber ( fiber ) ;
1961
+ resetCurrentDebugFiberInDEV ( ) ;
1962
+ }
1963
+
1964
+ const sibling = fiber . sibling ;
1965
+ if ( sibling !== null ) {
1966
+ ensureCorrectReturnPointer ( sibling , fiber . return ) ;
1967
+ nextEffect = sibling ;
1968
+ return ;
1969
+ }
1970
+
1971
+ nextEffect = fiber . return ;
1972
+ }
1973
+ }
1974
+
1975
+ function commitPassiveUnmountOnFiber ( finishedWork : Fiber ) : void {
1976
+ if ( __DEV__ ) {
1977
+ finishedWork . flags &= ~ PassiveUnmountPendingDev ;
1978
+ const alternate = finishedWork . alternate ;
1979
+ if ( alternate !== null ) {
1980
+ alternate . flags &= ~ PassiveUnmountPendingDev ;
1981
+ }
1982
+ }
1983
+
1984
+ switch ( finishedWork . tag ) {
1985
+ case FunctionComponent :
1986
+ case ForwardRef :
1987
+ case SimpleMemoComponent : {
1988
+ if (
1989
+ enableProfilerTimer &&
1990
+ enableProfilerCommitHooks &&
1991
+ finishedWork . mode & ProfileMode
1992
+ ) {
1993
+ startPassiveEffectTimer ( ) ;
1994
+ commitHookEffectListUnmount ( HookPassive | HookHasEffect , finishedWork ) ;
1995
+ recordPassiveEffectDuration ( finishedWork ) ;
1996
+ } else {
1997
+ commitHookEffectListUnmount ( HookPassive | HookHasEffect , finishedWork ) ;
1998
+ }
1999
+ break ;
2000
+ }
2001
+ }
2002
+ }
2003
+
2004
+ function commitPassiveUnmountEffectsInsideOfDeletedTree_begin (
2005
+ deletedSubtreeRoot : Fiber ,
2006
+ ) {
2007
+ while ( nextEffect !== null ) {
2008
+ const fiber = nextEffect ;
2009
+ const child = fiber . child ;
2010
+ if ( ( fiber . subtreeFlags & PassiveStatic ) !== NoFlags && child !== null ) {
2011
+ ensureCorrectReturnPointer ( child , fiber ) ;
2012
+ nextEffect = child ;
2013
+ } else {
2014
+ commitPassiveUnmountEffectsInsideOfDeletedTree_complete (
2015
+ deletedSubtreeRoot ,
2016
+ ) ;
2017
+ }
2018
+ }
2019
+ }
2020
+
2021
+ function commitPassiveUnmountEffectsInsideOfDeletedTree_complete (
2022
+ deletedSubtreeRoot : Fiber ,
2023
+ ) {
2024
+ while ( nextEffect !== null ) {
2025
+ const fiber = nextEffect ;
2026
+ if ( ( fiber . flags & PassiveStatic ) !== NoFlags ) {
2027
+ setCurrentDebugFiberInDEV ( fiber ) ;
2028
+ commitPassiveUnmountInsideDeletedTreeOnFiber ( fiber ) ;
2029
+ resetCurrentDebugFiberInDEV ( ) ;
2030
+ }
2031
+
2032
+ if ( fiber === deletedSubtreeRoot ) {
2033
+ nextEffect = null ;
2034
+ return ;
2035
+ }
2036
+
2037
+ const sibling = fiber . sibling ;
2038
+ if ( sibling !== null ) {
2039
+ ensureCorrectReturnPointer ( sibling , fiber . return ) ;
2040
+ nextEffect = sibling ;
2041
+ return ;
2042
+ }
2043
+
2044
+ nextEffect = fiber . return ;
2045
+ }
2046
+ }
2047
+
2048
+ function commitPassiveUnmountInsideDeletedTreeOnFiber ( current : Fiber ) : void {
2049
+ switch ( current . tag ) {
2050
+ case FunctionComponent :
2051
+ case ForwardRef :
2052
+ case SimpleMemoComponent : {
2053
+ if (
2054
+ enableProfilerTimer &&
2055
+ enableProfilerCommitHooks &&
2056
+ current . mode & ProfileMode
2057
+ ) {
2058
+ startPassiveEffectTimer ( ) ;
2059
+ commitHookEffectListUnmount ( HookPassive , current ) ;
2060
+ recordPassiveEffectDuration ( current ) ;
2061
+ } else {
2062
+ commitHookEffectListUnmount ( HookPassive , current ) ;
2063
+ }
2064
+ break ;
2065
+ }
2066
+ }
2067
+ }
2068
+
1917
2069
let didWarnWrongReturnPointer = false ;
1918
2070
function ensureCorrectReturnPointer ( fiber , expectedReturnFiber ) {
1919
2071
if ( __DEV__ ) {
0 commit comments