Zustand persist rehydration completes after first render
0 reputation · 03 Feb 2021, 11:27 UTC
0 reputation · 03 Feb 2021, 11:27 UTC
This question concerns Zustand's persist middleware and whether rehydrated state is available before the first component render. The goal is to diagnose whether recovered data from localStorage is guaranteed to exist when a selector-based component mounts, or whether the component always renders with the initial state until rehydration completes.
Persist rehydrates asynchronously, and onRehydrateStorage exposes start and finished events. Zustand does not document a synchronous readiness guarantee for restored state across supported releases. It is unclear whether reading persisted values during initial render is safe or whether rendering must wait for the finished callback.
Does onRehydrateStorage finished fire before any mounted component reads the store? Can a selector safely return persisted state during the first render? Is there a synchronous rehydration guarantee in current Zustand versions?
35775 reputation · 03 Feb 2021, 15:39 UTC
No to all three. The onRehydrateStorage callback does not fire before the first mounted component reads the store. A selector cannot safely return persisted state during the initial render. Zustand does not provide a synchronous rehydration guarantee across supported releases, even when the underlying storage is synchronous.
Likely explanation: The persist middleware defers state merging until after store creation, so the initial render cycle completes before rehydration finishes. The middleware treats rehydration as an asynchronous side effect regardless of whether the storage backend is synchronous.
Confirmed behavior: Selectors read synchronously from the current store snapshot. Until rehydration completes and the persisted state is merged, the snapshot reflects the initial state passed to the store creator. The onRehydrateStorage listener is invoked before rehydration begins, and its returned callback runs after rehydration completes—after the initial render.
false.true inside the onRehydrateStorage callback.Alternatively, use skipHydration: true and call the returned rehydrate function manually in a useEffect before rendering dependent children.
This behavior is consistent across Zustand v4 and v5, though the exact onRehydrateStorage callback signature differs between releases. Check your installed version in package.json and inspect the persist middleware source for your release.
To verify the timing in your project, build a minimal store with persist and a mocked localStorage. Log the render order alongside the rehydration callback. You should observe the initial render preceding hydration. If you need to eliminate the initial default-state read entirely, test a skipHydration store with a manual rehydrate call in useEffect.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.