Back

Zustand: client-side persistence

Modern web applications often need to store data client-side, e.g. to preserve authentication credentials on page reload.

It's easy to just write data to localStorage/sessionStorage - but inevitably that data influences rendering; naive solutions don't automatically keep views and persisted data in sync.

Zustand comes with persistence middleware out of the box, which can automatically synchronize in-memory data and its persisted counterpart.

Examples

Keeping zustand in sync with localStorage/sessionStorage

Zustand supports middleware for a variety of purposes - including automatically staying in sync with localStorage/sessionStorage.

The example below leverages the storage middleware; it writes to localStorage - so the value will be kept intact as the page is refreshed or opened on a different tab in the same browser.

Zustand Persistence via Middleware
  • Relies on useLocalStorageCounter
  • Which leverages Zustand's built-in middleware for storing data in localStorage
  • Requires a client-side hydration step when used in tandem with SSR
  • This component is rendered with a hydration step, so is SSR-compatible

Writing to sessionStorage

Zustand's persistence middleware defaults to localStorage. It's possible to configure writing to any storage on a per-store basis, though.

In the example below, the middleware writes to sessionStorage - which means the data is preserved across refreshes, but is only available to a single tab.

Zustand middleware-based persistence: sessionStorage
  • Relies on useSessionStorageCounter
  • Writes to sessionStorage, instead of the default localStorage
  • Data survives refreshes, but will not be available on a new tab

Zustand + SSR/NextJS: Hydrating Persisted Data

There's a caveat to be aware of when relying on Zustand to stay in sync with a persisted client-side store.

With Server-Side React (SSR), components may be rendered on the backend - which would not have access to the front end data. This would lead to a data consistency issue.

The two examples above handle this concern by wrapping the view dependent on Zustand's persistence middleware with HydratingLoader.

The component in this example does not wait for hydration before rendering - so changing the value below will lead to errors printed to the browser's JS console on page reload. It's stored in sessionStorage, so the errors will only persist within one tab.

Zustand Persistence Middleware + NextJS: Hydration
  • Persists data with Zustand's persist middleware
  • The page is rendered server-side via NextJS, which reads the default value from zustand (0)
  • When the page is rendered browser-side, zustand reads from sessionStorage, which may have a different value
  • If the page is refreshed, the inconsistency will cause an error to pop up in the browser's JS console
-
0
+