last update
Jun 2, 2026
license
MITv1.0.0
format
SKILL.md
- Install
// Downloads SKILL.md into ~/.claude/skills/zustand-state-manager/
$ curl -fsSL --create-dirs -o ~/.claude/skills/zustand-state-manager/SKILL.md https://claudeskil.com/skills/zustand-state-manager/SKILL.md - Invoke
// Inside Claude Code, type the skill name as a slash command
> /zustand-state-manager give my landing page a hero treatment - Or copy this from the README
// extracted ts block
$ import { create } from 'zustand' import { devtools, persist, createJSONStorage } from 'zustand/middleware' import { immer } from 'zustand/middleware/immer' import { useShallow } from 'zustand/react/shallow' const useStore = create<CartState>()(
- name:
- Zustand State Manager
- slug:
- zustand-state-manager
- version:
- v1.0.0
- license:
- MIT
- author:
- @chiragthummar16
- categories:
- tags:
- #zustand#state-management#react#immer#persist
- description:
Zustand stores — slices, persistence, devtools, immer middleware, selectors that don't re-render.
README.md
Zustand State Manager
A focused skill for building production Zustand stores the way the library is actually meant to be used: composed slices, middleware stacks, and selectors that don't trigger needless re-renders. It's aimed at React and Next.js developers who have outgrown a single flat create() store and want patterns that scale without a Redux-sized rewrite.
When to use it
- Your store has grown past one file and you want to split it into independent slices that still share one root state.
- Components re-render on every store change and you need fine-grained, atomic subscriptions.
- You need state to survive reloads via
localStorage,sessionStorage, AsyncStorage, or IndexedDB. - You're on the Next.js App Router and hit hydration mismatches or "store shared between requests" bugs.
- You want time-travel debugging through Redux DevTools, or ergonomic nested updates without spread soup.
What it does
The skill applies the canonical middleware-composed API: create()(devtools(persist(immer(...)))). It generates slice creators typed as StateCreator<RootState, [], [], Slice> and merges them in one root store. For reads it favors atomic selectors — useStore(s => s.count) — plus useShallow for object/array selections and createWithEqualityFn when you need a custom comparator. Persistence is wired through persist with createJSONStorage, partialize to whitelist keys, version + migrate for schema changes, and onRehydrateStorage callbacks. immer middleware enables draft-style mutations inside set. For Next.js it uses the per-request store factory pattern with a React context provider so server and client stay isolated.
Usage
curl -fsSL --create-dirs -o ~/.claude/skills/zustand-state-manager/SKILL.md https://claudeskil.com/skills/zustand-state-manager/SKILL.md
import { create } from 'zustand'
import { devtools, persist, createJSONStorage } from 'zustand/middleware'
import { immer } from 'zustand/middleware/immer'
import { useShallow } from 'zustand/react/shallow'
const useStore = create<CartState>()(
devtools(
persist(
immer((set) => ({
items: [],
add: (p) => set((s) => { s.items.push(p) }), // immer draft
})),
{ name: 'cart', storage: createJSONStorage(() => localStorage),
partialize: (s) => ({ items: s.items }) }
)
)
)
// only re-renders when ids change
const ids = useStore(useShallow((s) => s.items.map((i) => i.id)))
Tips & gotchas
- Always call
create<T>()(...)with the empty parens — that curried form is required for TypeScript to infer middleware types. useShallowonly does a one-level shallow compare; for deeper structures reach forcreateWithEqualityFnwith a customequalityFn.- Selecting a freshly built object/array (e.g.
s => ({a, b})) withoutuseShallowcauses infinite re-renders — the reference changes every call. - Bump
persist'sversionwhenever the persisted shape changes and supplymigrate, or rehydration silently fails.
FAQ
Do I need Redux Toolkit instead? No. Zustand covers slices, devtools, and persistence without actions/reducers boilerplate or a Provider (except the SSR pattern).
How do I read state outside React? Use useStore.getState() / useStore.setState() / useStore.subscribe() — the vanilla store works anywhere.
Why hydration errors in Next.js? A module-level store leaks across requests. Use a per-request factory + context provider so each render gets a fresh store.
$ cat reviews/