AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Zustand State

skill-deadlymind-nanolama-zustand-state · by Deadlymind

Client-only UI state stores with Zustand for Next.js 16 App Router and React 19 — a small typed create() store, persist middleware with partialize to save only IDs and UI prefs (never fetched server objects), and an isHydrated/skipHydration guard to avoid SSR hydration mismatches. Use when adding a Zustand store, persisting a sidebar/theme/filter/selection to localStorage, fixing a "Text content…

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

Install

$ agentstack add skill-deadlymind-nanolama-zustand-state

✓ 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 No
  • 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.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-deadlymind-nanolama-zustand-state)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
24d ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Zustand State? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Zustand state (client UI state, not server data)

When to use

You need ephemeral, client-owned UI state that outlives a single component: theme, sidebar open/closed, a wizard step, active filters, or the id of a selected row. If the value comes from the API, it does not belong here.

Pattern

Two rules, held everywhere:

  1. Zustand holds UI state; React Query holds server state. Never mirror

fetched objects into a store — cache them with react-query and keep only references (ids, selection, prefs) in Zustand. Duplicated server data goes stale and desyncs.

  1. Persist is opt-in and narrow. Use persist + partialize to save only

the UI prefs/ids you actually want across reloads, and guard hydration so the server-rendered HTML matches the first client render.

Steps / idioms

  1. A small, typed store — state plus the actions that mutate it, colocated.

Persist narrowly with partialize, and note the hydration hooks used below:

```ts // stores/ui.ts import { create } from "zustand"; import { persist, createJSONStorage } from "zustand/middleware";

type UIState = { sidebarOpen: boolean; activeEntrepriseId: string | null; // an id/reference, NOT the fetched object toggleSidebar: () => void; setEntreprise: (id: string | null) => void; };

// create()(...) — the extra () is required for TS inference with middleware export const useUI = create()( persist( (set) => ({ sidebarOpen: true, activeEntrepriseId: null, toggleSidebar: () => set((s) => ({ sidebarOpen: !s.sidebarOpen })), setEntreprise: (id) => set({ activeEntrepriseId: id }), }), { name: "ui", // unique per store, avoids localStorage key collisions storage: createJSONStorage(() => localStorage), // persist ONLY prefs + ids; never fetched server lists/objects partialize: (s) => ({ sidebarOpen: s.sidebarOpen, activeEntrepriseId: s.activeEntrepriseId, }), }, ), ); ```

  1. Guard hydration so SSR and the first client paint agree. Track a hydrated

flag with useState/useEffect — seed it from useUI.persist.hasHydrated() and subscribe via useUI.persist.onFinishHydration(() => …) (it returns an unsubscribe). Render a neutral default until hydrated is true, then read useUI(...); this prevents the "Text content did not match" warning.

  1. Select narrow slices (useUI((s) => s.sidebarOpen)), not the whole store,

so components re-render only on the fields they read.

Variants

  • Manual rehydration. Set skipHydration: true in the persist options and

call useUI.persist.rehydrate() yourself (e.g. after reading a cookie or the server-known tenant), instead of the automatic-on-mount default.

  • Non-persisted store. Drop the persist wrapper entirely for pure

in-memory UI state (a modal, a drag position) — no hydration guard needed.

Adapt to your repo

Rename activeEntrepriseId and the store to your domain, and set a unique persist name per store to avoid localStorage key collisions. Confirm the store file is client-side (imported only from "use client" components). Bump the persist version and add a migrate fn when you change persisted shape. If you also use Zustand outside Next.js, the hydration guard is only needed where SSR renders the component.

Gotchas

  • Persisting fetched server objects is the classic bug — they go stale and

fight react-query; persist ids/prefs only via partialize.

  • Reading persisted state during the first render without the hydration guard

causes "Text content did not match" / hydration-mismatch warnings.

  • create()(...) needs the extra call parens (curried form) for correct

TypeScript inference with middleware — a common copy error.

  • One module-level store is shared across all users in the same tab; never put

per-request secrets or another tenant's data in it.

See also

  • react-query
  • nextjs-module

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.