Skip to content

feat(persist): Suspense-based rehydration with React 19 use() hook #1015

@ctrlplusb

Description

@ctrlplusb

Summary

Modernize the persistence rehydration flow to leverage React 19's use() hook for Suspense integration, and wrap rehydration state replacement in startTransition for non-blocking hydration.

Parent issue: #1004

Background

useStoreRehydrated (hooks.js:81-90) currently uses the useState + useEffect pattern:

function useStoreRehydrated() {
  const [rehydrated, setRehydrated] = useState(false);
  useEffect(() => {
    store.persist.resolveRehydration().then(() => setRehydrated(true));
  }, []);
  return rehydrated;
}

This requires manual if (!rehydrated) checks in consumer code. React 19's use() hook enables Suspense integration instead.

Changes

1. Rewrite useStoreRehydrated using use()

  • Replace useState + useEffect with use(store.persist.resolveRehydration())
  • Enables <Suspense fallback={<Loading/>}> around rehydrating stores
  • The current resolveRehydration() already returns a stable Promise (create-store.js:169)

2. Wrap rehydration replaceState in startTransition

  • create-store.js:53 — the replaceState call during rehydration is a large state swap
  • Wrapping in startTransition prevents it from blocking the UI

React version strategy

This requires a decision on React 19 support approach:

  • Option A: Bump minimum peer dependency to React 19 (breaking change)
  • Option B: Conditional export (easy-peasy/react19) with the use()-based hook
  • Option C: Runtime feature detection (typeof React.use === 'function')

The startTransition portion is React 18 compatible and can land independently.

Testing

  • Test Suspense boundary integration with useStoreRehydrated
  • Test with async storage backends (the main rehydration path)
  • Test startTransition wrapping doesn't break rehydration ordering
  • Regression test existing useStoreRehydrated behavior

Metadata

Metadata

Assignees

Labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions