Skip to content

feat(react): modernize useSyncExternalStore usage for React 18+#1021

Merged
ctrlplusb merged 1 commit intov7-devfrom
1013-usesyncexternalstore-modernize
May 4, 2026
Merged

feat(react): modernize useSyncExternalStore usage for React 18+#1021
ctrlplusb merged 1 commit intov7-devfrom
1013-usesyncexternalstore-modernize

Conversation

@ctrlplusb
Copy link
Copy Markdown
Owner

Summary

Refs #1004. Implements the P0 recommendations from the React primitives investigation: drop the use-sync-external-store shim, modernize useLocalStore, and add the 'use client' directive for RSC compatibility.

Deferred React 18/19 primitive work (use(), startTransition, useStoreTransition, useStoreDeferredState, useOptimistic, etc.) is tracked separately in #1020.

Changes

  • src/hooks.js — drop the use-sync-external-store shim; use native useSyncExternalStore from react and inline the with-selector logic (mirrors React's reference implementation). Remove the initializeUseStoreState indirection — no longer needed since React 18+ is the floor (per peerDependencies).
  • src/use-local-store.js — migrate from raw useState + subscribe to useSyncExternalStore to prevent tearing in concurrent mode.
  • src/index.js — remove shim init plumbing.
  • rollup.config.js — add 'use client'; banner to ESM and CJS outputs so the bundled package works correctly in React Server Components environments (Next.js App Router etc). Rollup strips module-level directives, so the banner is the correct mechanism.
  • package.json — remove use-sync-external-store from runtime dependencies.

Notes

  • No public API changes.
  • Selector + isEqual semantics are preserved exactly (the inlined useSyncExternalStoreWithSelector is a direct port of React's reference implementation).
  • The two eslint-disable react-hooks/exhaustive-deps annotations in src/hooks.js cover an intentional pattern where inst is a mutable ref container (not a reactive dependency) — same omission present in upstream React.

- Drop use-sync-external-store shim; use native useSyncExternalStore
  from react and inline the with-selector logic (mirrors React's
  reference implementation).
- Remove initializeUseStoreState indirection — no longer needed since
  React 18+ is the floor (per peerDependencies).
- Migrate useLocalStore from raw useState/subscribe to useSyncExternalStore
  to prevent tearing in concurrent mode.
- Add 'use client' banner to ESM and CJS bundles via Rollup so the
  package works correctly in React Server Components environments
  (Next.js App Router etc).
- Remove use-sync-external-store from runtime dependencies.

Refs #1004. Deferred React 18/19 primitive work tracked in #1020.
@vercel
Copy link
Copy Markdown

vercel Bot commented May 4, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
easy-peasy Ready Ready Preview, Comment May 4, 2026 2:05am

@ctrlplusb ctrlplusb changed the base branch from master to v7-dev May 4, 2026 02:05
@ctrlplusb ctrlplusb merged commit 25f55b3 into v7-dev May 4, 2026
9 checks passed
@ctrlplusb ctrlplusb deleted the 1013-usesyncexternalstore-modernize branch May 4, 2026 02:06
ctrlplusb added a commit that referenced this pull request May 4, 2026
- Drop use-sync-external-store shim; use native useSyncExternalStore
  from react and inline the with-selector logic (mirrors React's
  reference implementation).
- Remove initializeUseStoreState indirection — no longer needed since
  React 18+ is the floor (per peerDependencies).
- Migrate useLocalStore from raw useState/subscribe to useSyncExternalStore
  to prevent tearing in concurrent mode.
- Add 'use client' banner to ESM and CJS bundles via Rollup so the
  package works correctly in React Server Components environments
  (Next.js App Router etc).
- Remove use-sync-external-store from runtime dependencies.

Refs #1004. Deferred React 18/19 primitive work tracked in #1020.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant