Skip to content

Commit d046c96

Browse files
committed
Toggle visibility of Suspense children in mutation phase, not layout
If parent reads visibility of children in a lifecycle, they should have already updated.
1 parent 8fab1de commit d046c96

File tree

2 files changed

+62
-24
lines changed

2 files changed

+62
-24
lines changed

packages/react-reconciler/src/ReactFiberCommitWork.js

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -449,30 +449,8 @@ function commitLifeCycles(
449449
}
450450
return;
451451
}
452-
case SuspenseComponent: {
453-
let newState: SuspenseState | null = finishedWork.memoizedState;
454-
455-
let newDidTimeout;
456-
let primaryChildParent = finishedWork;
457-
if (newState === null) {
458-
newDidTimeout = false;
459-
} else {
460-
newDidTimeout = true;
461-
primaryChildParent = finishedWork.child;
462-
if (newState.timedOutAt === NoWork) {
463-
// If the children had not already timed out, record the time.
464-
// This is used to compute the elapsed time during subsequent
465-
// attempts to render the children.
466-
newState.timedOutAt = requestCurrentTime();
467-
}
468-
}
469-
470-
if (primaryChildParent !== null) {
471-
hideOrUnhideAllChildren(primaryChildParent, newDidTimeout);
472-
}
473-
474-
return;
475-
}
452+
case SuspenseComponent:
453+
break;
476454
case IncompleteClassComponent:
477455
break;
478456
default: {
@@ -1043,6 +1021,26 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
10431021
return;
10441022
}
10451023
case SuspenseComponent: {
1024+
let newState: SuspenseState | null = finishedWork.memoizedState;
1025+
1026+
let newDidTimeout;
1027+
let primaryChildParent = finishedWork;
1028+
if (newState === null) {
1029+
newDidTimeout = false;
1030+
} else {
1031+
newDidTimeout = true;
1032+
primaryChildParent = finishedWork.child;
1033+
if (newState.timedOutAt === NoWork) {
1034+
// If the children had not already timed out, record the time.
1035+
// This is used to compute the elapsed time during subsequent
1036+
// attempts to render the children.
1037+
newState.timedOutAt = requestCurrentTime();
1038+
}
1039+
}
1040+
1041+
if (primaryChildParent !== null) {
1042+
hideOrUnhideAllChildren(primaryChildParent, newDidTimeout);
1043+
}
10461044
return;
10471045
}
10481046
case IncompleteClassComponent: {

packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1717
beforeEach(() => {
1818
jest.resetModules();
1919
ReactFeatureFlags = require('shared/ReactFeatureFlags');
20+
ReactFeatureFlags.enableHooks = true;
2021
ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false;
2122
ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false;
2223
React = require('react');
@@ -1378,6 +1379,45 @@ describe('ReactSuspenseWithNoopRenderer', () => {
13781379
await advanceTimers(100);
13791380
expect(ReactNoop.getChildren()).toEqual([span('Hi')]);
13801381
});
1382+
1383+
it('toggles visibility during the mutation phase', async () => {
1384+
const {useRef, useLayoutEffect} = React;
1385+
1386+
function Parent() {
1387+
const child = useRef(null);
1388+
1389+
useLayoutEffect(() => {
1390+
ReactNoop.yield('Child is hidden: ' + child.current.hidden);
1391+
});
1392+
1393+
return (
1394+
<span ref={child} hidden={false}>
1395+
<AsyncText ms={1000} text="Hi" />
1396+
</span>
1397+
);
1398+
}
1399+
1400+
function App(props) {
1401+
return (
1402+
<Suspense fallback={<Text text="Loading..." />}>
1403+
<Parent />
1404+
</Suspense>
1405+
);
1406+
}
1407+
1408+
ReactNoop.renderLegacySyncRoot(<App middleText="B" />);
1409+
1410+
expect(ReactNoop.clearYields()).toEqual([
1411+
'Suspend! [Hi]',
1412+
'Loading...',
1413+
// The child should have already been hidden
1414+
'Child is hidden: true',
1415+
]);
1416+
1417+
await advanceTimers(1000);
1418+
1419+
expect(ReactNoop.clearYields()).toEqual(['Promise resolved [Hi]', 'Hi']);
1420+
});
13811421
});
13821422

13831423
it('does not call lifecycles of a suspended component', async () => {

0 commit comments

Comments
 (0)