Skip to content
_______________________
V.1.0.0 // SECURE CONNECTION
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.

Share

"End of transmission."

[CLOSE_CONSTRUCT]