Zustand
Client state management with typed stores and devtools middleware.
Overview
Adds Zustand for lightweight client-side state with typed stores, Redux DevTools, and optional persistence.
Prerequisites
None.
Installation
npx ds-start init my-app --zustand
# or add to existing project
npx ds-start add zustandWhat It Adds
lib/stores/counter.ts— Example typed store with devtoolslib/stores/index.ts— Barrel export for all stores
Environment Variables
None required.
Usage
Creating a store
Stores are defined with full type safety and devtools middleware:
import { create } from "zustand"
import { devtools } from "zustand/middleware"
interface CounterState {
count: number
increment: () => void
decrement: () => void
reset: () => void
}
export const useCounterStore = create<CounterState>()(
devtools(
(set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
reset: () => set({ count: 0 }),
}),
{ name: "counter" },
),
)Using in a component
Select individual values to avoid unnecessary re-renders:
"use client"
import { useCounterStore } from "@/lib/stores"
export function Counter() {
const count = useCounterStore((s) => s.count)
const increment = useCounterStore((s) => s.increment)
const decrement = useCounterStore((s) => s.decrement)
const reset = useCounterStore((s) => s.reset)
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
<button onClick={reset}>Reset</button>
</div>
)
}Adding persistence
Use the persist middleware to save state to localStorage:
import { create } from "zustand"
import { devtools, persist } from "zustand/middleware"
interface ThemeState {
theme: "light" | "dark"
toggle: () => void
}
export const useThemeStore = create<ThemeState>()(
devtools(
persist(
(set) => ({
theme: "light",
toggle: () =>
set((state) => ({
theme: state.theme === "light" ? "dark" : "light",
})),
}),
{ name: "theme-storage" },
),
{ name: "theme" },
),
)Adding a new store
- Create a new file in
lib/stores/:
import { create } from "zustand"
import { devtools } from "zustand/middleware"
interface UserState {
name: string | null
email: string | null
setUser: (name: string, email: string) => void
clearUser: () => void
}
export const useUserStore = create<UserState>()(
devtools(
(set) => ({
name: null,
email: null,
setUser: (name, email) => set({ name, email }),
clearUser: () => set({ name: null, email: null }),
}),
{ name: "user" },
),
)- Export from the barrel file:
export { useCounterStore } from "./counter"
export { useUserStore } from "./user"