@@ -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 {
@@ -1897,62 +1898,50 @@ export function isSuspenseBoundaryBeingHidden(
18971898
18981899export function commitMutationEffects (
18991900 root : FiberRoot ,
1900- firstChild : Fiber ,
1901+ finishedWork : Fiber ,
19011902 committedLanes : Lanes ,
19021903) {
19031904 inProgressLanes = committedLanes ;
19041905 inProgressRoot = root ;
1905- nextEffect = firstChild ;
1906+ nextEffect = finishedWork ;
19061907
1907- commitMutationEffects_begin ( root , committedLanes ) ;
1908+ setCurrentDebugFiberInDEV ( finishedWork ) ;
1909+ commitMutationEffectsOnFiber ( finishedWork , root , committedLanes ) ;
1910+ setCurrentDebugFiberInDEV ( finishedWork ) ;
19081911
19091912 inProgressLanes = null ;
19101913 inProgressRoot = null ;
19111914}
19121915
1913- function commitMutationEffects_begin ( root : FiberRoot , lanes : Lanes ) {
1914- while ( nextEffect !== null ) {
1915- const fiber = nextEffect ;
1916-
1917- // TODO: Should wrap this in flags check, too, as optimization
1918- const deletions = fiber . deletions ;
1919- if ( deletions !== null ) {
1920- for ( let i = 0 ; i < deletions . length ; i ++ ) {
1921- const childToDelete = deletions [ i ] ;
1922- try {
1923- commitDeletion ( root , childToDelete , fiber ) ;
1924- } catch ( error ) {
1925- captureCommitPhaseError ( childToDelete , fiber , error ) ;
1926- }
1916+ function recursivelyTraverseMutationEffects (
1917+ root : FiberRoot ,
1918+ parentFiber : Fiber ,
1919+ lanes : Lanes ,
1920+ ) {
1921+ // Deletions effects can be scheduled on any fiber type. They need to happen
1922+ // before the children effects hae fired.
1923+ const deletions = parentFiber . deletions ;
1924+ if ( deletions !== null ) {
1925+ for ( let i = 0 ; i < deletions . length ; i ++ ) {
1926+ const childToDelete = deletions [ i ] ;
1927+ try {
1928+ commitDeletion ( root , childToDelete , parentFiber ) ;
1929+ } catch ( error ) {
1930+ captureCommitPhaseError ( childToDelete , parentFiber , error ) ;
19271931 }
19281932 }
1929-
1930- const child = fiber . child ;
1931- if ( ( fiber . subtreeFlags & MutationMask ) !== NoFlags && child !== null ) {
1932- child . return = fiber ;
1933- nextEffect = child ;
1934- } else {
1935- commitMutationEffects_complete ( root , lanes ) ;
1936- }
19371933 }
1938- }
19391934
1940- function commitMutationEffects_complete ( root : FiberRoot , lanes : Lanes ) {
1941- while ( nextEffect !== null ) {
1942- const fiber = nextEffect ;
1943- setCurrentDebugFiberInDEV ( fiber ) ;
1944- commitMutationEffectsOnFiber ( fiber , root , lanes ) ;
1945- resetCurrentDebugFiberInDEV ( ) ;
1946-
1947- const sibling = fiber . sibling ;
1948- if ( sibling !== null ) {
1949- sibling . return = fiber . return ;
1950- nextEffect = sibling ;
1951- return ;
1935+ const prevDebugFiber = getCurrentDebugFiberInDEV ( ) ;
1936+ if ( parentFiber . subtreeFlags & MutationMask ) {
1937+ let child = parentFiber . child ;
1938+ while ( child !== null ) {
1939+ setCurrentDebugFiberInDEV ( child ) ;
1940+ commitMutationEffectsOnFiber ( child , root , lanes ) ;
1941+ child = child . sibling ;
19521942 }
1953-
1954- nextEffect = fiber . return ;
19551943 }
1944+ setCurrentDebugFiberInDEV ( prevDebugFiber ) ;
19561945}
19571946
19581947function commitMutationEffectsOnFiber (
@@ -1971,6 +1960,7 @@ function commitMutationEffectsOnFiber(
19711960 case ForwardRef :
19721961 case MemoComponent :
19731962 case SimpleMemoComponent : {
1963+ recursivelyTraverseMutationEffects ( root , finishedWork , lanes ) ;
19741964 commitReconciliationEffects ( finishedWork ) ;
19751965
19761966 if ( flags & Update ) {
@@ -2023,6 +2013,7 @@ function commitMutationEffectsOnFiber(
20232013 return ;
20242014 }
20252015 case ClassComponent : {
2016+ recursivelyTraverseMutationEffects ( root , finishedWork , lanes ) ;
20262017 commitReconciliationEffects ( finishedWork ) ;
20272018
20282019 if ( flags & Ref ) {
@@ -2033,6 +2024,7 @@ function commitMutationEffectsOnFiber(
20332024 return ;
20342025 }
20352026 case HostComponent : {
2027+ recursivelyTraverseMutationEffects ( root , finishedWork , lanes ) ;
20362028 commitReconciliationEffects ( finishedWork ) ;
20372029
20382030 if ( flags & Ref ) {
@@ -2041,7 +2033,13 @@ function commitMutationEffectsOnFiber(
20412033 }
20422034 }
20432035 if ( supportsMutation ) {
2044- if ( flags & ContentReset ) {
2036+ // TODO: ContentReset gets cleared by the children during the commit
2037+ // phase. This is a refactor hazard because it means we must read
2038+ // flags the flags after `commitReconciliationEffects` has already run;
2039+ // the order matters. We should refactor so that ContentReset does not
2040+ // rely on mutating the flag during commit. Like by setting a flag
2041+ // during the render phase instead.
2042+ if ( finishedWork . flags & ContentReset ) {
20452043 const instance : Instance = finishedWork . stateNode ;
20462044 try {
20472045 resetTextContent ( instance ) ;
@@ -2088,6 +2086,7 @@ function commitMutationEffectsOnFiber(
20882086 return ;
20892087 }
20902088 case HostText : {
2089+ recursivelyTraverseMutationEffects ( root , finishedWork , lanes ) ;
20912090 commitReconciliationEffects ( finishedWork ) ;
20922091
20932092 if ( flags & Update ) {
@@ -2117,6 +2116,7 @@ function commitMutationEffectsOnFiber(
21172116 return ;
21182117 }
21192118 case HostRoot : {
2119+ recursivelyTraverseMutationEffects ( root , finishedWork , lanes ) ;
21202120 commitReconciliationEffects ( finishedWork ) ;
21212121
21222122 // TODO: Add a flag check and move to passive phase. Luna's PR fixes this.
@@ -2176,6 +2176,7 @@ function commitMutationEffectsOnFiber(
21762176 return ;
21772177 }
21782178 case HostPortal : {
2179+ recursivelyTraverseMutationEffects ( root , finishedWork , lanes ) ;
21792180 commitReconciliationEffects ( finishedWork ) ;
21802181
21812182 if ( flags & Update ) {
@@ -2193,6 +2194,7 @@ function commitMutationEffectsOnFiber(
21932194 return ;
21942195 }
21952196 case SuspenseComponent : {
2197+ recursivelyTraverseMutationEffects ( root , finishedWork , lanes ) ;
21962198 commitReconciliationEffects ( finishedWork ) ;
21972199
21982200 if ( flags & Visibility ) {
@@ -2217,6 +2219,7 @@ function commitMutationEffectsOnFiber(
22172219 return ;
22182220 }
22192221 case OffscreenComponent : {
2222+ recursivelyTraverseMutationEffects ( root , finishedWork , lanes ) ;
22202223 commitReconciliationEffects ( finishedWork ) ;
22212224
22222225 if ( flags & Visibility ) {
@@ -2254,6 +2257,7 @@ function commitMutationEffectsOnFiber(
22542257 return ;
22552258 }
22562259 case SuspenseListComponent : {
2260+ recursivelyTraverseMutationEffects ( root , finishedWork , lanes ) ;
22572261 commitReconciliationEffects ( finishedWork ) ;
22582262
22592263 if ( flags & Update ) {
@@ -2262,6 +2266,7 @@ function commitMutationEffectsOnFiber(
22622266 return ;
22632267 }
22642268 case ScopeComponent : {
2269+ recursivelyTraverseMutationEffects ( root , finishedWork , lanes ) ;
22652270 commitReconciliationEffects ( finishedWork ) ;
22662271
22672272 if ( enableScopeAPI ) {
@@ -2278,11 +2283,13 @@ function commitMutationEffectsOnFiber(
22782283 return ;
22792284 }
22802285 default : {
2286+ recursivelyTraverseMutationEffects ( root , finishedWork , lanes ) ;
22812287 commitReconciliationEffects ( finishedWork ) ;
2288+
2289+ return ;
22822290 }
22832291 }
22842292}
2285-
22862293function commitReconciliationEffects ( finishedWork : Fiber ) {
22872294 // Placement effects (insertions, reorders) can be scheduled on any fiber
22882295 // type. They needs to happen after the children effects have fired, but
0 commit comments