diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index 5f17ca31b36..1e75bf53f0d 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -4349,16 +4349,20 @@ function flushRenderPhaseStrictModeWarningsInDEV() { function recursivelyTraverseAndDoubleInvokeEffectsInDEV( root: FiberRoot, parentFiber: Fiber, + treeFlags: Flags, isInStrictMode: boolean, ) { - if ((parentFiber.subtreeFlags & (PlacementDEV | Visibility)) === NoFlags) { + if ( + ((treeFlags | parentFiber.subtreeFlags) & (PlacementDEV | Visibility)) === + NoFlags + ) { // Parent's descendants have already had effects double invoked. // Early exit to avoid unnecessary tree traversal. return; } let child = parentFiber.child; while (child !== null) { - doubleInvokeEffectsInDEVIfNecessary(root, child, isInStrictMode); + doubleInvokeEffectsInDEVIfNecessary(root, child, treeFlags, isInStrictMode); child = child.sibling; } } @@ -4387,6 +4391,7 @@ function doubleInvokeEffectsOnFiber( function doubleInvokeEffectsInDEVIfNecessary( root: FiberRoot, fiber: Fiber, + treeFlags: Flags, parentIsInStrictMode: boolean, ) { const isStrictModeFiber = fiber.type === REACT_STRICT_MODE_TYPE; @@ -4395,7 +4400,7 @@ function doubleInvokeEffectsInDEVIfNecessary( // First case: the fiber **is not** of type OffscreenComponent. No // special rules apply to double invoking effects. if (fiber.tag !== OffscreenComponent) { - if (fiber.flags & PlacementDEV) { + if ((treeFlags | fiber.flags) & PlacementDEV) { if (isInStrictMode) { runWithFiberInDEV( fiber, @@ -4404,14 +4409,15 @@ function doubleInvokeEffectsInDEVIfNecessary( fiber, (fiber.mode & NoStrictPassiveEffectsMode) === NoMode, ); + return; } - } else { - recursivelyTraverseAndDoubleInvokeEffectsInDEV( - root, - fiber, - isInStrictMode, - ); } + recursivelyTraverseAndDoubleInvokeEffectsInDEV( + root, + fiber, + treeFlags | fiber.flags, + isInStrictMode, + ); return; } @@ -4432,6 +4438,7 @@ function doubleInvokeEffectsInDEVIfNecessary( recursivelyTraverseAndDoubleInvokeEffectsInDEV, root, fiber, + treeFlags | fiber.flags, isInStrictMode, ); } @@ -4455,6 +4462,7 @@ function commitDoubleInvokeEffectsInDEV( recursivelyTraverseAndDoubleInvokeEffectsInDEV( root, root.current, + root.current.flags, doubleInvokeEffects, ); } else { diff --git a/packages/react/src/__tests__/ReactStrictMode-test.internal.js b/packages/react/src/__tests__/ReactStrictMode-test.internal.js index 2867e064837..d3061bc3c3f 100644 --- a/packages/react/src/__tests__/ReactStrictMode-test.internal.js +++ b/packages/react/src/__tests__/ReactStrictMode-test.internal.js @@ -206,11 +206,10 @@ describe('ReactStrictMode', () => { 'B: useLayoutEffect mount', 'A: useEffect mount', 'B: useEffect mount', - // TODO: this is currently broken - // 'B: useLayoutEffect unmount', - // 'B: useEffect unmount', - // 'B: useLayoutEffect mount', - // 'B: useEffect mount', + 'B: useLayoutEffect unmount', + 'B: useEffect unmount', + 'B: useLayoutEffect mount', + 'B: useEffect mount', ]); }); }