Return_to_vault
[CONSTRUCT: 2026-01-30]
Zustand Persist Pattern
ReactTypeScriptState Management
Zustand Persist Pattern
Two patterns in one file: a basic typed store and one with localStorage persistence via Zustand's middleware. This is the 80/20 of React state management. You get type safety, zero boilerplate, and optional persistence without touching Redux, context providers, or any of that ceremony.
When to Use
- You need shared state in React but Redux is overkill for the use case
- Persisting user preferences (theme, sidebar state, settings) across page reloads
- Any store where you want the API to be "create a hook, use the hook"
The Code
import { create } from 'zustand'
import { persist } from 'zustand/middleware'
// Basic typed store (no persistence)
interface LoadingState {
isLoading: boolean
setIsLoading: (isLoading: boolean) => void
}
export const useLoadingStore = create<LoadingState>((set) => ({
isLoading: true,
setIsLoading: (isLoading) => set({ isLoading }),
}))
// With persistence middleware (localStorage)
interface UserPreferences {
theme: 'light' | 'dark'
sidebarOpen: boolean
setTheme: (theme: 'light' | 'dark') => void
toggleSidebar: () => void
}
export const usePreferencesStore = create<UserPreferences>()(
persist(
(set) => ({
theme: 'dark',
sidebarOpen: true,
setTheme: (theme) => set({ theme }),
toggleSidebar: () => set((s) => ({ sidebarOpen: !s.sidebarOpen })),
}),
{ name: 'user-preferences' }
)
)
Notes
The persist middleware hydrates from localStorage on mount, which means there's a brief flash where the store has default values. If that matters for your UI (like theme flickering), read the persisted value directly from localStorage in your layout before React hydrates.