@@ -84,6 +84,7 @@ import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFrom
8484import {
8585 resetCurrentFiber as resetCurrentDebugFiberInDEV ,
8686 setCurrentFiber as setCurrentDebugFiberInDEV ,
87+ getCurrentFiber as getCurrentDebugFiberInDEV ,
8788} from './ReactCurrentFiber' ;
8889import { resolveDefaultProps } from './ReactFiberLazyComponent.new' ;
8990import {
@@ -1901,62 +1902,50 @@ export function isSuspenseBoundaryBeingHidden(
19011902
19021903export function commitMutationEffects (
19031904 root : FiberRoot ,
1904- firstChild : Fiber ,
1905+ finishedWork : Fiber ,
19051906 committedLanes : Lanes ,
19061907) {
19071908 inProgressLanes = committedLanes ;
19081909 inProgressRoot = root ;
1909- nextEffect = firstChild ;
1910+ nextEffect = finishedWork ;
19101911
1911- commitMutationEffects_begin ( root , committedLanes ) ;
1912+ setCurrentDebugFiberInDEV ( finishedWork ) ;
1913+ commitMutationEffectsOnFiber ( finishedWork , root , committedLanes ) ;
1914+ setCurrentDebugFiberInDEV ( finishedWork ) ;
19121915
19131916 inProgressLanes = null ;
19141917 inProgressRoot = null ;
19151918}
19161919
1917- function commitMutationEffects_begin ( root : FiberRoot , lanes : Lanes ) {
1918- while ( nextEffect !== null ) {
1919- const fiber = nextEffect ;
1920-
1921- // TODO: Should wrap this in flags check, too, as optimization
1922- const deletions = fiber . deletions ;
1923- if ( deletions !== null ) {
1924- for ( let i = 0 ; i < deletions . length ; i ++ ) {
1925- const childToDelete = deletions [ i ] ;
1926- try {
1927- commitDeletion ( root , childToDelete , fiber ) ;
1928- } catch ( error ) {
1929- captureCommitPhaseError ( childToDelete , fiber , error ) ;
1930- }
1920+ function recursivelyTraverseMutationEffects (
1921+ root : FiberRoot ,
1922+ parentFiber : Fiber ,
1923+ lanes : Lanes ,
1924+ ) {
1925+ // Deletions effects can be scheduled on any fiber type. They need to happen
1926+ // before the children effects hae fired.
1927+ const deletions = parentFiber . deletions ;
1928+ if ( deletions !== null ) {
1929+ for ( let i = 0 ; i < deletions . length ; i ++ ) {
1930+ const childToDelete = deletions [ i ] ;
1931+ try {
1932+ commitDeletion ( root , childToDelete , parentFiber ) ;
1933+ } catch ( error ) {
1934+ captureCommitPhaseError ( childToDelete , parentFiber , error ) ;
19311935 }
19321936 }
1933-
1934- const child = fiber . child ;
1935- if ( ( fiber . subtreeFlags & MutationMask ) !== NoFlags && child !== null ) {
1936- child . return = fiber ;
1937- nextEffect = child ;
1938- } else {
1939- commitMutationEffects_complete ( root , lanes ) ;
1940- }
19411937 }
1942- }
19431938
1944- function commitMutationEffects_complete ( root : FiberRoot , lanes : Lanes ) {
1945- while ( nextEffect !== null ) {
1946- const fiber = nextEffect ;
1947- setCurrentDebugFiberInDEV ( fiber ) ;
1948- commitMutationEffectsOnFiber ( fiber , root , lanes ) ;
1949- resetCurrentDebugFiberInDEV ( ) ;
1950-
1951- const sibling = fiber . sibling ;
1952- if ( sibling !== null ) {
1953- sibling . return = fiber . return ;
1954- nextEffect = sibling ;
1955- return ;
1939+ const prevDebugFiber = getCurrentDebugFiberInDEV ( ) ;
1940+ if ( parentFiber . subtreeFlags & MutationMask ) {
1941+ let child = parentFiber . child ;
1942+ while ( child !== null ) {
1943+ setCurrentDebugFiberInDEV ( child ) ;
1944+ commitMutationEffectsOnFiber ( child , root , lanes ) ;
1945+ child = child . sibling ;
19561946 }
1957-
1958- nextEffect = fiber . return ;
19591947 }
1948+ setCurrentDebugFiberInDEV ( prevDebugFiber ) ;
19601949}
19611950
19621951function commitMutationEffectsOnFiber (
@@ -1975,6 +1964,7 @@ function commitMutationEffectsOnFiber(
19751964 case ForwardRef :
19761965 case MemoComponent :
19771966 case SimpleMemoComponent : {
1967+ recursivelyTraverseMutationEffects ( root , finishedWork , lanes ) ;
19781968 commitReconciliationEffects ( finishedWork ) ;
19791969
19801970 if ( flags & Update ) {
@@ -2027,6 +2017,7 @@ function commitMutationEffectsOnFiber(
20272017 return ;
20282018 }
20292019 case ClassComponent : {
2020+ recursivelyTraverseMutationEffects ( root , finishedWork , lanes ) ;
20302021 commitReconciliationEffects ( finishedWork ) ;
20312022
20322023 if ( flags & Ref ) {
@@ -2037,6 +2028,7 @@ function commitMutationEffectsOnFiber(
20372028 return ;
20382029 }
20392030 case HostComponent : {
2031+ recursivelyTraverseMutationEffects ( root , finishedWork , lanes ) ;
20402032 commitReconciliationEffects ( finishedWork ) ;
20412033
20422034 if ( flags & Ref ) {
@@ -2045,7 +2037,13 @@ function commitMutationEffectsOnFiber(
20452037 }
20462038 }
20472039 if ( supportsMutation ) {
2048- if ( flags & ContentReset ) {
2040+ // TODO: ContentReset gets cleared by the children during the commit
2041+ // phase. This is a refactor hazard because it means we must read
2042+ // flags the flags after `commitReconciliationEffects` has already run;
2043+ // the order matters. We should refactor so that ContentReset does not
2044+ // rely on mutating the flag during commit. Like by setting a flag
2045+ // during the render phase instead.
2046+ if ( finishedWork . flags & ContentReset ) {
20492047 const instance : Instance = finishedWork . stateNode ;
20502048 try {
20512049 resetTextContent ( instance ) ;
@@ -2092,6 +2090,7 @@ function commitMutationEffectsOnFiber(
20922090 return ;
20932091 }
20942092 case HostText : {
2093+ recursivelyTraverseMutationEffects ( root , finishedWork , lanes ) ;
20952094 commitReconciliationEffects ( finishedWork ) ;
20962095
20972096 if ( flags & Update ) {
@@ -2121,6 +2120,7 @@ function commitMutationEffectsOnFiber(
21212120 return ;
21222121 }
21232122 case HostRoot : {
2123+ recursivelyTraverseMutationEffects ( root , finishedWork , lanes ) ;
21242124 commitReconciliationEffects ( finishedWork ) ;
21252125
21262126 if ( flags & Update ) {
@@ -2153,6 +2153,7 @@ function commitMutationEffectsOnFiber(
21532153 return ;
21542154 }
21552155 case HostPortal : {
2156+ recursivelyTraverseMutationEffects ( root , finishedWork , lanes ) ;
21562157 commitReconciliationEffects ( finishedWork ) ;
21572158
21582159 if ( flags & Update ) {
@@ -2170,6 +2171,7 @@ function commitMutationEffectsOnFiber(
21702171 return ;
21712172 }
21722173 case SuspenseComponent : {
2174+ recursivelyTraverseMutationEffects ( root , finishedWork , lanes ) ;
21732175 commitReconciliationEffects ( finishedWork ) ;
21742176
21752177 if ( flags & Visibility ) {
@@ -2194,6 +2196,7 @@ function commitMutationEffectsOnFiber(
21942196 return ;
21952197 }
21962198 case OffscreenComponent : {
2199+ recursivelyTraverseMutationEffects ( root , finishedWork , lanes ) ;
21972200 commitReconciliationEffects ( finishedWork ) ;
21982201
21992202 if ( flags & Visibility ) {
@@ -2231,6 +2234,7 @@ function commitMutationEffectsOnFiber(
22312234 return ;
22322235 }
22332236 case SuspenseListComponent : {
2237+ recursivelyTraverseMutationEffects ( root , finishedWork , lanes ) ;
22342238 commitReconciliationEffects ( finishedWork ) ;
22352239
22362240 if ( flags & Update ) {
@@ -2240,6 +2244,7 @@ function commitMutationEffectsOnFiber(
22402244 }
22412245 case ScopeComponent : {
22422246 if ( enableScopeAPI ) {
2247+ recursivelyTraverseMutationEffects ( root , finishedWork , lanes ) ;
22432248 commitReconciliationEffects ( finishedWork ) ;
22442249
22452250 // TODO: This is a temporary solution that allowed us to transition away
@@ -2258,11 +2263,13 @@ function commitMutationEffectsOnFiber(
22582263 return ;
22592264 }
22602265 default : {
2266+ recursivelyTraverseMutationEffects ( root , finishedWork , lanes ) ;
22612267 commitReconciliationEffects ( finishedWork ) ;
2268+
2269+ return ;
22622270 }
22632271 }
22642272}
2265-
22662273function commitReconciliationEffects ( finishedWork : Fiber ) {
22672274 // Placement effects (insertions, reorders) can be scheduled on any fiber
22682275 // type. They needs to happen after the children effects have fired, but
0 commit comments