Skip to content

Commit a598a71

Browse files
committed
Prevent infinite re-render in StrictMode + Offscreen
1 parent a9dc73c commit a598a71

File tree

3 files changed

+37
-2
lines changed

3 files changed

+37
-2
lines changed

packages/react-reconciler/src/ReactFiberWorkLoop.new.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ import {
124124
LayoutMask,
125125
PassiveMask,
126126
PlacementDEV,
127+
Visibility,
127128
} from './ReactFiberFlags';
128129
import {
129130
NoLanes,
@@ -3184,7 +3185,10 @@ function doubleInvokeEffectsInDEV(
31843185
) {
31853186
const isStrictModeFiber = fiber.type === REACT_STRICT_MODE_TYPE;
31863187
const isInStrictMode = parentIsInStrictMode || isStrictModeFiber;
3187-
if (fiber.flags & PlacementDEV || fiber.tag === OffscreenComponent) {
3188+
if (
3189+
fiber.flags & PlacementDEV ||
3190+
(fiber.tag === OffscreenComponent && fiber.flags & Visibility)
3191+
) {
31883192
setCurrentDebugFiberInDEV(fiber);
31893193
if (isInStrictMode) {
31903194
disappearLayoutEffects(fiber);

packages/react-reconciler/src/ReactFiberWorkLoop.old.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ import {
124124
LayoutMask,
125125
PassiveMask,
126126
PlacementDEV,
127+
Visibility,
127128
} from './ReactFiberFlags';
128129
import {
129130
NoLanes,
@@ -3184,7 +3185,10 @@ function doubleInvokeEffectsInDEV(
31843185
) {
31853186
const isStrictModeFiber = fiber.type === REACT_STRICT_MODE_TYPE;
31863187
const isInStrictMode = parentIsInStrictMode || isStrictModeFiber;
3187-
if (fiber.flags & PlacementDEV || fiber.tag === OffscreenComponent) {
3188+
if (
3189+
fiber.flags & PlacementDEV ||
3190+
(fiber.tag === OffscreenComponent && fiber.flags & Visibility)
3191+
) {
31883192
setCurrentDebugFiberInDEV(fiber);
31893193
if (isInStrictMode) {
31903194
disappearLayoutEffects(fiber);

packages/react-reconciler/src/__tests__/ReactOffscreenStrictMode-test.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,4 +92,31 @@ describe('ReactOffscreenStrictMode', () => {
9292
'A: useEffect mount',
9393
]);
9494
});
95+
96+
it('should not cause infinite render loop when StrictMode is used with Suspense and synchronous set states', () => {
97+
// This is a regression test, see https://github.com/facebook/react/pull/25179 for more details.
98+
function App() {
99+
const [state, setState] = React.useState(false);
100+
101+
React.useLayoutEffect(() => {
102+
setState(true);
103+
}, []);
104+
105+
React.useEffect(() => {
106+
// Empty useEffect with empty dependency array is needed to trigger infinite render loop.
107+
}, []);
108+
109+
return state;
110+
}
111+
112+
act(() => {
113+
ReactNoop.render(
114+
<React.StrictMode>
115+
<React.Suspense>
116+
<App />
117+
</React.Suspense>
118+
</React.StrictMode>,
119+
);
120+
});
121+
});
95122
});

0 commit comments

Comments
 (0)