Skip to content

Commit a2bfae1

Browse files
committed
fix suspense throttling
1 parent b8cfda1 commit a2bfae1

File tree

3 files changed

+71
-16
lines changed

3 files changed

+71
-16
lines changed

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

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2250,22 +2250,25 @@ function commitMutationEffectsOnFiber(
22502250
}
22512251
}
22522252

2253-
if (flags & Visibility) {
2254-
switch (finishedWork.tag) {
2255-
case SuspenseComponent: {
2256-
const newState: OffscreenState | null = finishedWork.memoizedState;
2253+
switch (finishedWork.tag) {
2254+
case SuspenseComponent: {
2255+
const offscreenFiber: Fiber = (finishedWork.child: any);
2256+
if (offscreenFiber.flags & Visibility) {
2257+
const newState: OffscreenState | null = offscreenFiber.memoizedState;
22572258
const isHidden = newState !== null;
22582259
if (isHidden) {
2259-
const current = finishedWork.alternate;
2260+
const current = offscreenFiber.alternate;
22602261
const wasHidden = current !== null && current.memoizedState !== null;
22612262
if (!wasHidden) {
22622263
// TODO: Move to passive phase
22632264
markCommitTimeOfFallback();
22642265
}
22652266
}
2266-
break;
22672267
}
2268-
case OffscreenComponent: {
2268+
break;
2269+
}
2270+
case OffscreenComponent: {
2271+
if (flags & Visibility) {
22692272
const newState: OffscreenState | null = finishedWork.memoizedState;
22702273
const isHidden = newState !== null;
22712274
const current = finishedWork.alternate;
@@ -2301,7 +2304,6 @@ function commitMutationEffectsOnFiber(
23012304
}
23022305
}
23032306
}
2304-
23052307
// The following switch statement is only concerned about placement,
23062308
// updates, and deletions. To avoid needing to add a case for every possible
23072309
// bitmap value, we remove the secondary effects from the effect tag and

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

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2250,22 +2250,25 @@ function commitMutationEffectsOnFiber(
22502250
}
22512251
}
22522252

2253-
if (flags & Visibility) {
2254-
switch (finishedWork.tag) {
2255-
case SuspenseComponent: {
2256-
const newState: OffscreenState | null = finishedWork.memoizedState;
2253+
switch (finishedWork.tag) {
2254+
case SuspenseComponent: {
2255+
const offscreenFiber: Fiber = (finishedWork.child: any);
2256+
if (offscreenFiber.flags & Visibility) {
2257+
const newState: OffscreenState | null = offscreenFiber.memoizedState;
22572258
const isHidden = newState !== null;
22582259
if (isHidden) {
2259-
const current = finishedWork.alternate;
2260+
const current = offscreenFiber.alternate;
22602261
const wasHidden = current !== null && current.memoizedState !== null;
22612262
if (!wasHidden) {
22622263
// TODO: Move to passive phase
22632264
markCommitTimeOfFallback();
22642265
}
22652266
}
2266-
break;
22672267
}
2268-
case OffscreenComponent: {
2268+
break;
2269+
}
2270+
case OffscreenComponent: {
2271+
if (flags & Visibility) {
22692272
const newState: OffscreenState | null = finishedWork.memoizedState;
22702273
const isHidden = newState !== null;
22712274
const current = finishedWork.alternate;
@@ -2301,7 +2304,6 @@ function commitMutationEffectsOnFiber(
23012304
}
23022305
}
23032306
}
2304-
23052307
// The following switch statement is only concerned about placement,
23062308
// updates, and deletions. To avoid needing to add a case for every possible
23072309
// bitmap value, we remove the secondary effects from the effect tag and

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

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,57 @@ describe('ReactSuspense', () => {
285285
expect(root).toMatchRenderedOutput('AsyncAfter SuspenseSibling');
286286
});
287287

288+
it('globally throttles fallback committing', () => {
289+
function Foo() {
290+
Scheduler.unstable_yieldValue('Foo');
291+
return (
292+
<Suspense fallback={<Text text="Loading..." />}>
293+
<AsyncText text="A" ms={200} />
294+
<Suspense fallback={<Text text="Loading more..." />}>
295+
<AsyncText text="B" ms={300} />
296+
</Suspense>
297+
</Suspense>
298+
);
299+
}
300+
301+
// throttling works on fallback committing
302+
// here advance some time to skip the first threshold
303+
jest.advanceTimersByTime(600);
304+
Scheduler.unstable_advanceTime(600);
305+
306+
const root = ReactTestRenderer.create(<Foo />, {
307+
unstable_isConcurrent: true,
308+
});
309+
310+
expect(Scheduler).toFlushAndYield([
311+
'Foo',
312+
'Suspend! [A]',
313+
'Suspend! [B]',
314+
'Loading more...',
315+
'Loading...',
316+
]);
317+
expect(root).toMatchRenderedOutput('Loading...');
318+
319+
// resolve A
320+
jest.advanceTimersByTime(200);
321+
Scheduler.unstable_advanceTime(200);
322+
expect(Scheduler).toHaveYielded(['Promise resolved [A]']);
323+
expect(Scheduler).toFlushAndYield(['A', 'Suspend! [B]', 'Loading more...']);
324+
325+
// should still renders previous fallback
326+
expect(root).toMatchRenderedOutput('Loading...');
327+
328+
// resolve B
329+
jest.advanceTimersByTime(100);
330+
Scheduler.unstable_advanceTime(100);
331+
expect(Scheduler).toHaveYielded(['Promise resolved [B]']);
332+
333+
// before commiting we still shows previous fallback
334+
expect(root).toMatchRenderedOutput('Loading...');
335+
expect(Scheduler).toFlushAndYield(['A', 'B']);
336+
expect(root).toMatchRenderedOutput('AB');
337+
});
338+
288339
// @gate !enableSyncDefaultUpdates
289340
it(
290341
'interrupts current render when something suspends with a ' +

0 commit comments

Comments
 (0)