Skip to content

// Zustand stores — slices, persistence, devtools, immer middleware, selectors that don't re-render.

Zustand State Manager

skill --stat
  • last update

    Jun 2, 2026

  • license

    MITv1.0.0

  • format

    SKILL.md

quickstart.sh
3 steps
  1. 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
  2. Invoke

    // Inside Claude Code, type the skill name as a slash command

    > /zustand-state-manager give my landing page a hero treatment
  3. 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>()(
zustand-state-manager/
references
SKILL.md
readonly
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/README.md
6 sections

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

bash
curl -fsSL --create-dirs -o ~/.claude/skills/zustand-state-manager/SKILL.md https://claudeskil.com/skills/zustand-state-manager/SKILL.md
ts
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.
  • useShallow only does a one-level shallow compare; for deeper structures reach for createWithEqualityFn with a custom equalityFn.
  • Selecting a freshly built object/array (e.g. s => ({a, b})) without useShallow causes infinite re-renders — the reference changes every call.
  • Bump persist's version whenever the persisted shape changes and supply migrate, 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/

Reviews

// No reviews yet. Be the first.
Loading review form…

$ ls related/

explore all →