Skip to content

Commit 90aa765

Browse files
committed
Exclude hydration from nested update check
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.
1 parent 79d4fec commit 90aa765

File tree

2 files changed

+21
-2
lines changed

2 files changed

+21
-2
lines changed

packages/react-reconciler/src/ReactFiberLane.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ export const InputContinuousLane: Lane = /* */ 0b0000000000000000000
4646
export const DefaultHydrationLane: Lane = /* */ 0b0000000000000000000000000010000;
4747
export const DefaultLane: Lane = /* */ 0b0000000000000000000000000100000;
4848

49-
export const SyncUpdateLanes: Lane = /* */ 0b0000000000000000000000000101010;
49+
export const SyncUpdateLanes: Lane = enableUnifiedSyncLane
50+
? SyncLane | InputContinuousLane | DefaultLane
51+
: SyncLane;
5052

5153
const TransitionHydrationLane: Lane = /* */ 0b0000000000000000000000001000000;
5254
const TransitionLanes: Lanes = /* */ 0b0000000011111111111111110000000;
@@ -84,6 +86,11 @@ export const IdleLane: Lane = /* */ 0b0100000000000000000
8486

8587
export const OffscreenLane: Lane = /* */ 0b1000000000000000000000000000000;
8688

89+
// Any lane that might schedule an update. This is used to detect infinite
90+
// update loops, so it doesn't include hydration lanes or retries.
91+
export const UpdateLanes: Lanes =
92+
SyncLane | InputContinuousLane | DefaultLane | TransitionLanes;
93+
8794
// This function is used for the experimental timeline (react-devtools-timeline)
8895
// It should be kept in sync with the Lanes values above.
8996
export function getLabelForLane(lane: Lane): string | void {

packages/react-reconciler/src/ReactFiberWorkLoop.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ import {
154154
includesOnlyNonUrgentLanes,
155155
includesSomeLane,
156156
OffscreenLane,
157+
SyncUpdateLanes,
158+
UpdateLanes,
157159
} from './ReactFiberLane';
158160
import {
159161
DiscreteEventPriority,
@@ -2932,7 +2934,17 @@ function commitRootImpl(
29322934

29332935
// Read this again, since a passive effect might have updated it
29342936
remainingLanes = root.pendingLanes;
2935-
if (includesSyncLane(remainingLanes)) {
2937+
2938+
// Check if this render scheduled a cascading synchronous update. This is a
2939+
// heurstic to detect infinite update loops. We are intentionally excluding
2940+
// hydration lanes in this check, because render triggered by selective
2941+
// hydration is conceptually not an update.
2942+
if (
2943+
// Was the finished render the result of an update (not hydration)?
2944+
includesSomeLane(lanes, UpdateLanes) &&
2945+
// Did it schedule a sync update?
2946+
includesSomeLane(remainingLanes, SyncUpdateLanes)
2947+
) {
29362948
if (enableProfilerTimer && enableProfilerNestedUpdatePhase) {
29372949
markNestedUpdateScheduled();
29382950
}

0 commit comments

Comments
 (0)