From 3b5c917acec0dcbe2962a2af9c6c49c73205dceb Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Fri, 29 Sep 2023 13:54:55 -0400 Subject: [PATCH] Exclude hydration from nested update check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a commit was the result of selective hydration, we should not increment the nested update count, because those renders conceptually are not updates. Ideally, they wouldn't even be in a separate commit — we should be able to hydrate a tree and apply an update on top of it within the same render phase. We could do this once we implement resumable context stacks. --- packages/react-reconciler/src/ReactFiberLane.js | 4 +++- packages/react-reconciler/src/ReactFiberWorkLoop.js | 13 ++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberLane.js b/packages/react-reconciler/src/ReactFiberLane.js index 51126c6cdbcc4..a61a8b9fcd0fe 100644 --- a/packages/react-reconciler/src/ReactFiberLane.js +++ b/packages/react-reconciler/src/ReactFiberLane.js @@ -46,7 +46,9 @@ export const InputContinuousLane: Lane = /* */ 0b0000000000000000000 export const DefaultHydrationLane: Lane = /* */ 0b0000000000000000000000000010000; export const DefaultLane: Lane = /* */ 0b0000000000000000000000000100000; -export const SyncUpdateLanes: Lane = /* */ 0b0000000000000000000000000101010; +export const SyncUpdateLanes: Lane = enableUnifiedSyncLane + ? SyncLane | InputContinuousLane | DefaultLane + : SyncLane; const TransitionHydrationLane: Lane = /* */ 0b0000000000000000000000001000000; const TransitionLanes: Lanes = /* */ 0b0000000011111111111111110000000; diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index f6f09f470b432..9102c10e14637 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -154,6 +154,7 @@ import { includesOnlyNonUrgentLanes, includesSomeLane, OffscreenLane, + SyncUpdateLanes, } from './ReactFiberLane'; import { DiscreteEventPriority, @@ -2932,7 +2933,17 @@ function commitRootImpl( // Read this again, since a passive effect might have updated it remainingLanes = root.pendingLanes; - if (includesSyncLane(remainingLanes)) { + + // Check if this render scheduled a cascading synchronous update. This is a + // heurstic to detect infinite update loops. We are intentionally excluding + // hydration lanes in this check, because render triggered by selective + // hydration is conceptually not an update. + if ( + // Was the finished render the result of a sync update? + includesSomeLane(lanes, SyncUpdateLanes) && + // Did is schedule another sync update? + includesSomeLane(remainingLanes, SyncUpdateLanes) + ) { if (enableProfilerTimer && enableProfilerNestedUpdatePhase) { markNestedUpdateScheduled(); }