Skip to content

Commit b45ac12

Browse files
committed
Schedule work to update Context.Consumer inside Suspense
1 parent fb36d98 commit b45ac12

File tree

2 files changed

+140
-0
lines changed

2 files changed

+140
-0
lines changed

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

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,12 @@ import type {SharedQueue} from './ReactUpdateQueue.new';
2020
import {isPrimaryRenderer} from './ReactFiberHostConfig';
2121
import {createCursor, push, pop} from './ReactFiberStack.new';
2222
import {
23+
ContextConsumer,
2324
ContextProvider,
2425
ClassComponent,
2526
DehydratedFragment,
27+
OffscreenComponent,
28+
SuspenseComponent,
2629
} from './ReactWorkTags';
2730
import {
2831
NoLanes,
@@ -157,6 +160,10 @@ export function scheduleWorkOnParentPath(
157160
!isSubsetOfLanes(alternate.childLanes, renderLanes)
158161
) {
159162
alternate.childLanes = mergeLanes(alternate.childLanes, renderLanes);
163+
} else {
164+
// Neither alternate was updated, which means the rest of the
165+
// ancestor path already has sufficient priority.
166+
break;
160167
}
161168
node = node.return;
162169
}
@@ -361,6 +368,69 @@ function propagateContextChanges<T>(
361368
}
362369
scheduleWorkOnParentPath(consumer.return, renderLanes);
363370

371+
// If Context.Consumer is a descendant of Suspense,
372+
// `scheduleWorkOnParentPath` may break before it get to Suspense.
373+
// Schedule work to avoid bailout before Context.Consumer receives the value.
374+
const primaryChildFragment = workInProgress.child;
375+
if (
376+
workInProgress.tag === SuspenseComponent &&
377+
primaryChildFragment !== null &&
378+
primaryChildFragment.tag === OffscreenComponent &&
379+
consumer.tag === ContextConsumer
380+
) {
381+
const workInProgressAlternate = workInProgress.alternate;
382+
if (!isSubsetOfLanes(workInProgress.childLanes, renderLanes)) {
383+
workInProgress.childLanes = mergeLanes(
384+
workInProgress.childLanes,
385+
renderLanes,
386+
);
387+
if (workInProgressAlternate !== null) {
388+
workInProgressAlternate.childLanes = mergeLanes(
389+
workInProgressAlternate.childLanes,
390+
renderLanes,
391+
);
392+
}
393+
} else if (
394+
workInProgressAlternate !== null &&
395+
!isSubsetOfLanes(
396+
workInProgressAlternate.childLanes,
397+
renderLanes,
398+
)
399+
) {
400+
workInProgressAlternate.childLanes = mergeLanes(
401+
workInProgressAlternate.childLanes,
402+
renderLanes,
403+
);
404+
}
405+
const primaryChildFragmentAlternate =
406+
primaryChildFragment.alternate;
407+
if (
408+
!isSubsetOfLanes(primaryChildFragment.childLanes, renderLanes)
409+
) {
410+
primaryChildFragment.childLanes = mergeLanes(
411+
primaryChildFragment.childLanes,
412+
renderLanes,
413+
);
414+
if (primaryChildFragmentAlternate !== null) {
415+
primaryChildFragmentAlternate.childLanes = mergeLanes(
416+
primaryChildFragmentAlternate.childLanes,
417+
renderLanes,
418+
);
419+
}
420+
} else if (
421+
primaryChildFragmentAlternate !== null &&
422+
!isSubsetOfLanes(
423+
primaryChildFragmentAlternate.childLanes,
424+
renderLanes,
425+
)
426+
) {
427+
primaryChildFragmentAlternate.childLanes = mergeLanes(
428+
primaryChildFragmentAlternate.childLanes,
429+
renderLanes,
430+
);
431+
}
432+
}
433+
364434
if (!forcePropagateEntireTree) {
365435
// During lazy propagation, when we find a match, we can defer
366436
// propagating changes to the children, because we're going to

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

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,12 @@ import type {SharedQueue} from './ReactUpdateQueue.old';
2020
import {isPrimaryRenderer} from './ReactFiberHostConfig';
2121
import {createCursor, push, pop} from './ReactFiberStack.old';
2222
import {
23+
ContextConsumer,
2324
ContextProvider,
2425
ClassComponent,
2526
DehydratedFragment,
27+
OffscreenComponent,
28+
SuspenseComponent,
2629
} from './ReactWorkTags';
2730
import {
2831
NoLanes,
@@ -157,6 +160,10 @@ export function scheduleWorkOnParentPath(
157160
!isSubsetOfLanes(alternate.childLanes, renderLanes)
158161
) {
159162
alternate.childLanes = mergeLanes(alternate.childLanes, renderLanes);
163+
} else {
164+
// Neither alternate was updated, which means the rest of the
165+
// ancestor path already has sufficient priority.
166+
break;
160167
}
161168
node = node.return;
162169
}
@@ -361,6 +368,69 @@ function propagateContextChanges<T>(
361368
}
362369
scheduleWorkOnParentPath(consumer.return, renderLanes);
363370

371+
// If Context.Consumer is a descendant of Suspense,
372+
// `scheduleWorkOnParentPath` may break before it get to Suspense.
373+
// Schedule work to avoid bailout before Context.Consumer receives the value.
374+
const primaryChildFragment = workInProgress.child;
375+
if (
376+
workInProgress.tag === SuspenseComponent &&
377+
primaryChildFragment !== null &&
378+
primaryChildFragment.tag === OffscreenComponent &&
379+
consumer.tag === ContextConsumer
380+
) {
381+
const workInProgressAlternate = workInProgress.alternate;
382+
if (!isSubsetOfLanes(workInProgress.childLanes, renderLanes)) {
383+
workInProgress.childLanes = mergeLanes(
384+
workInProgress.childLanes,
385+
renderLanes,
386+
);
387+
if (workInProgressAlternate !== null) {
388+
workInProgressAlternate.childLanes = mergeLanes(
389+
workInProgressAlternate.childLanes,
390+
renderLanes,
391+
);
392+
}
393+
} else if (
394+
workInProgressAlternate !== null &&
395+
!isSubsetOfLanes(
396+
workInProgressAlternate.childLanes,
397+
renderLanes,
398+
)
399+
) {
400+
workInProgressAlternate.childLanes = mergeLanes(
401+
workInProgressAlternate.childLanes,
402+
renderLanes,
403+
);
404+
}
405+
const primaryChildFragmentAlternate =
406+
primaryChildFragment.alternate;
407+
if (
408+
!isSubsetOfLanes(primaryChildFragment.childLanes, renderLanes)
409+
) {
410+
primaryChildFragment.childLanes = mergeLanes(
411+
primaryChildFragment.childLanes,
412+
renderLanes,
413+
);
414+
if (primaryChildFragmentAlternate !== null) {
415+
primaryChildFragmentAlternate.childLanes = mergeLanes(
416+
primaryChildFragmentAlternate.childLanes,
417+
renderLanes,
418+
);
419+
}
420+
} else if (
421+
primaryChildFragmentAlternate !== null &&
422+
!isSubsetOfLanes(
423+
primaryChildFragmentAlternate.childLanes,
424+
renderLanes,
425+
)
426+
) {
427+
primaryChildFragmentAlternate.childLanes = mergeLanes(
428+
primaryChildFragmentAlternate.childLanes,
429+
renderLanes,
430+
);
431+
}
432+
}
433+
364434
if (!forcePropagateEntireTree) {
365435
// During lazy propagation, when we find a match, we can defer
366436
// propagating changes to the children, because we're going to

0 commit comments

Comments
 (0)