From aea2754f55a327c8ae6a57d2156d43e9c10b019b Mon Sep 17 00:00:00 2001 From: okmttdhr Date: Sat, 8 May 2021 14:31:06 +0900 Subject: [PATCH] Schedule work to update Context.Consumer inside Suspense --- .../src/ReactFiberNewContext.new.js | 67 +++++++++++++++++++ .../src/ReactFiberNewContext.old.js | 4 ++ 2 files changed, 71 insertions(+) diff --git a/packages/react-reconciler/src/ReactFiberNewContext.new.js b/packages/react-reconciler/src/ReactFiberNewContext.new.js index c9933f2362ad3..2cf43cbe0d0e9 100644 --- a/packages/react-reconciler/src/ReactFiberNewContext.new.js +++ b/packages/react-reconciler/src/ReactFiberNewContext.new.js @@ -20,9 +20,12 @@ import type {SharedQueue} from './ReactUpdateQueue.new'; import {isPrimaryRenderer} from './ReactFiberHostConfig'; import {createCursor, push, pop} from './ReactFiberStack.new'; import { + ContextConsumer, ContextProvider, ClassComponent, DehydratedFragment, + OffscreenComponent, + SuspenseComponent, } from './ReactWorkTags'; import { NoLanes, @@ -157,6 +160,10 @@ export function scheduleWorkOnParentPath( !isSubsetOfLanes(alternate.childLanes, renderLanes) ) { alternate.childLanes = mergeLanes(alternate.childLanes, renderLanes); + } else { + // Neither alternate was updated, which means the rest of the + // ancestor path already has sufficient priority. + break; } node = node.return; } @@ -361,6 +368,66 @@ function propagateContextChanges( } scheduleWorkOnParentPath(consumer.return, renderLanes); + // If Context.Consumer is a descendant of Suspense, + // `scheduleWorkOnParentPath` may break before it get to Suspense. + // Schedule work to avoid bailout before Context.Consumer receives the value. + const contextConsumerIsDescendantOfSuspense = + workInProgress.tag === SuspenseComponent && + workInProgress.child.tag === OffscreenComponent && + consumer.tag === ContextConsumer; + if (contextConsumerIsDescendantOfSuspense) { + console.log(' contextConsumerWrappedBySuspense'); + if (!isSubsetOfLanes(workInProgress.childLanes, renderLanes)) { + workInProgress.childLanes = mergeLanes( + workInProgress.childLanes, + renderLanes, + ); + if (workInProgress.alternate !== null) { + workInProgress.alternate.childLanes = mergeLanes( + workInProgress.alternate.childLanes, + renderLanes, + ); + } + } else if ( + workInProgress.alternate !== null && + !isSubsetOfLanes( + workInProgress.alternate.childLanes, + renderLanes, + ) + ) { + workInProgress.alternate.childLanes = mergeLanes( + workInProgress.alternate.childLanes, + renderLanes, + ); + } + const primaryChildFragment = workInProgress.child; + if ( + !isSubsetOfLanes(primaryChildFragment.childLanes, renderLanes) + ) { + primaryChildFragment.childLanes = mergeLanes( + primaryChildFragment.childLanes, + renderLanes, + ); + if (primaryChildFragment.alternate !== null) { + primaryChildFragment.alternate.childLanes = mergeLanes( + primaryChildFragment.alternate.childLanes, + renderLanes, + ); + } + } else if ( + primaryChildFragment.alternate !== null && + !isSubsetOfLanes( + primaryChildFragment.alternate.childLanes, + renderLanes, + ) + ) { + primaryChildFragment.alternate.childLanes = mergeLanes( + primaryChildFragment.alternate.childLanes, + renderLanes, + ); + } + } + if (!forcePropagateEntireTree) { // During lazy propagation, when we find a match, we can defer // propagating changes to the children, because we're going to diff --git a/packages/react-reconciler/src/ReactFiberNewContext.old.js b/packages/react-reconciler/src/ReactFiberNewContext.old.js index daebdfd562798..c2a1600650119 100644 --- a/packages/react-reconciler/src/ReactFiberNewContext.old.js +++ b/packages/react-reconciler/src/ReactFiberNewContext.old.js @@ -157,6 +157,10 @@ export function scheduleWorkOnParentPath( !isSubsetOfLanes(alternate.childLanes, renderLanes) ) { alternate.childLanes = mergeLanes(alternate.childLanes, renderLanes); + } else { + // Neither alternate was updated, which means the rest of the + // ancestor path already has sufficient priority. + break; } node = node.return; }