AgentStack
SKILL verified MIT Self-run

Manage State With Zustand

skill-woliveiras-geremmyas-manage-state-with-zustand · by woliveiras

Zustand v5 recipes for middleware setup, immer mutations, persistence, and XState sync. Use when: zustand middleware, zustand persist, store patterns. Do not use: for state design patterns, non-Zustand stores.

No reviews yet
0 installs
13 views
0.0% view→install

Install

$ agentstack add skill-woliveiras-geremmyas-manage-state-with-zustand

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Manage State With Zustand? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Manage State with Zustand

Recipes for common Zustand v5 patterns. For core rules (when to use, store structure, middleware order, selectors), see the zustand instruction file which auto-loads for store files.

Middleware Setup

With persistence

create()(
  devtools(
    persist(
      immer((set) => ({
        // state
        items: [],
        // actions
        addItem: (item) => set((state) => { state.items.push(item) }),
        reset: () => set(() => ({ items: [] })),
      })),
      {
        name: "app-items",
        partialize: (state) => ({ items: state.items }),
      },
    ),
    { name: "ItemsStore", enabled: import.meta.env.DEV },
  ),
)

Without persistence

create()(
  devtools(
    immer((set) => ({
      count: 0,
      increment: () => set((state) => { state.count += 1 }),
    })),
    { name: "CounterStore", enabled: import.meta.env.DEV },
  ),
)

Immer Mutation Recipes

Update nested item

updateItem: (id, changes) =>
  set((state) => {
    const item = state.items.find((i) => i.id === id)
    if (item) Object.assign(item, changes)
  }),

Replace whole state (reset)

Return a new object instead of mutating:

reset: () => set(() => ({ ...DEFAULT_STATE })),

Toggle boolean

toggleDarkMode: () => set((state) => { state.darkMode = !state.darkMode }),

Syncing with XState

XState owns logic (transitions, guards, side effects). Zustand is the read cache for components. Sync in a Provider via subscription, not inside the machine:

useEffect(() => {
  const sub = actorRef.subscribe((snapshot) => {
    if (snapshot.matches("authenticated")) {
      useAuthStore.getState().setAuth(snapshot.context.user, snapshot.context.token)
    } else if (snapshot.matches("unauthenticated")) {
      useAuthStore.getState().clearAuth()
    }
  })
  return () => sub.unsubscribe()
}, [actorRef])

Key rules:

  • Subscribe in a React useEffect, not in the Zustand store definition
  • Use getState() to avoid stale closures
  • XState drives state transitions; Zustand reflects them for React consumption

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.