Skip to content

Commit

Permalink
Prevent infinite re-render in StrictMode + Offscreen
Browse files Browse the repository at this point in the history
  • Loading branch information
sammy-SC committed Sep 8, 2022
1 parent a9dc73c commit 3523be2
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 2 deletions.
6 changes: 5 additions & 1 deletion packages/react-reconciler/src/ReactFiberWorkLoop.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ import {
LayoutMask,
PassiveMask,
PlacementDEV,
Visibility,
} from './ReactFiberFlags';
import {
NoLanes,
Expand Down Expand Up @@ -3184,9 +3185,12 @@ function doubleInvokeEffectsInDEV(
) {
const isStrictModeFiber = fiber.type === REACT_STRICT_MODE_TYPE;
const isInStrictMode = parentIsInStrictMode || isStrictModeFiber;

if (fiber.flags & PlacementDEV || fiber.tag === OffscreenComponent) {
setCurrentDebugFiberInDEV(fiber);
if (isInStrictMode) {
const hasOffscreenVisibilityFlag =
fiber.tag !== OffscreenComponent || fiber.flags & Visibility;
if (isInStrictMode && hasOffscreenVisibilityFlag) {
disappearLayoutEffects(fiber);
disconnectPassiveEffect(fiber);
reappearLayoutEffects(root, fiber.alternate, fiber, false);
Expand Down
6 changes: 5 additions & 1 deletion packages/react-reconciler/src/ReactFiberWorkLoop.old.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ import {
LayoutMask,
PassiveMask,
PlacementDEV,
Visibility,
} from './ReactFiberFlags';
import {
NoLanes,
Expand Down Expand Up @@ -3184,9 +3185,12 @@ function doubleInvokeEffectsInDEV(
) {
const isStrictModeFiber = fiber.type === REACT_STRICT_MODE_TYPE;
const isInStrictMode = parentIsInStrictMode || isStrictModeFiber;

if (fiber.flags & PlacementDEV || fiber.tag === OffscreenComponent) {
setCurrentDebugFiberInDEV(fiber);
if (isInStrictMode) {
const hasOffscreenVisibilityFlag =
fiber.tag !== OffscreenComponent || fiber.flags & Visibility;
if (isInStrictMode && hasOffscreenVisibilityFlag) {
disappearLayoutEffects(fiber);
disconnectPassiveEffect(fiber);
reappearLayoutEffects(root, fiber.alternate, fiber, false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,21 @@ describe('ReactOffscreenStrictMode', () => {

log = [];

act(() => {
ReactNoop.render(
<React.StrictMode>
<Offscreen mode="hidden">
<Component label="A" />
<Component label="B" />
</Offscreen>
</React.StrictMode>,
);
});

expect(log).toEqual(['A: render', 'A: render', 'B: render', 'B: render']);

log = [];

act(() => {
ReactNoop.render(
<React.StrictMode>
Expand All @@ -92,4 +107,31 @@ describe('ReactOffscreenStrictMode', () => {
'A: useEffect mount',
]);
});

it('should not cause infinite render loop when StrictMode is used with Suspense and synchronous set states', () => {
// This is a regression test, see https://github.com/facebook/react/pull/25179 for more details.
function App() {
const [state, setState] = React.useState(false);

React.useLayoutEffect(() => {
setState(true);
}, []);

React.useEffect(() => {
// Empty useEffect with empty dependency array is needed to trigger infinite render loop.
}, []);

return state;
}

act(() => {
ReactNoop.render(
<React.StrictMode>
<React.Suspense>
<App />
</React.Suspense>
</React.StrictMode>,
);
});
});
});

0 comments on commit 3523be2

Please sign in to comment.