Skip to content

[Hooks] Keep hydrated content on post-hydration useSyncExternalStore patch-up (tests)#36592

Draft
devjiwonchoi wants to merge 1 commit into
facebook:mainfrom
devjiwonchoi:suspense-flicker-hydration-store
Draft

[Hooks] Keep hydrated content on post-hydration useSyncExternalStore patch-up (tests)#36592
devjiwonchoi wants to merge 1 commit into
facebook:mainfrom
devjiwonchoi:suspense-flicker-hydration-store

Conversation

@devjiwonchoi
Copy link
Copy Markdown

Summary

Draft, test-first. This PR adds the tests for an experimental feature behind enableHoldHydratedContentOnStoreSync (__EXPERIMENTAL__); the implementation lands in a follow-up. The tests pin the intended behavior.

Behavior: when the post-hydration useSyncExternalStore patch-up (the sync re-render that reconciles the client snapshot against the server snapshot we hydrated with) re-suspends an already-revealed Suspense boundary, keep the hydrated content instead of committing the fallback, treating that sync store update as delay-able like a transition. Scoped to the hydration reconcile window: steady-state sync store updates still flash the fallback. The hold covers the whole window (multiple in-window updates, not just the first), and is root-wide within the patch-up commit (atomic commit, like a transition).

Trade-off: while held, the boundary keeps content derived from the server snapshot even though the store has advanced to the client snapshot, so other non-suspending readers of the same store can show the newer value until the held boundary resolves.

Tests

packages/react-dom/src/__tests__/ReactDOMFizzShellHydration-test.js:

  • core keep-content, gated on/off
  • StrictMode double-invoked passive effects do not clear the hydration marker
  • marker cleared so a later steady-state update still flashes
  • no hold when client and server snapshots match at hydration
  • hold spans the whole reconcile window, not just the first update

packages/react-reconciler/src/__tests__/useSyncExternalStoreSuspenseFlicker-test.js:

  • scoping guard: a steady-state sync update still flashes the fallback

The gated assertions fall through to today's flash behavior until the flag and implementation land, so the suite is green on its own.

How did you test this?

yarn test and yarn test-stable for both files: 16/16 in each channel.

🤖 Generated with Claude Code

…e sync

Land the tests for enableHoldHydratedContentOnStoreSync before the flag and
implementation. When the post-hydration useSyncExternalStore patch-up (the
sync re-render that reconciles the client snapshot against the server snapshot
we hydrated with) suspends an already revealed Suspense boundary, the hydrated
content should be kept instead of flashing the fallback.

Coverage:
- core keep-content, gated on/off
- StrictMode double-invoked passive effects do not clear the hydration marker
- marker is cleared so a later steady-state update still flashes
- no hold when client and server snapshots match at hydration
- hold spans the whole reconcile window, not just the first update
- reconciler scoping guard: a steady-state sync update still flashes

The gated assertions fall through to today's flash behavior until the flag and
implementation land, so this commit passes on its own.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@meta-cla meta-cla Bot added the CLA Signed label Jun 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant