zustand

Guides Zustand store design with slices, reducers, selectors, and optimistic updates.

Updated Jan 27, 2026
One-click install
npx skills add https://github.com/SmallAi-API/smaihub --skill zustand-smallai-api
Or copy as Structured Prompt for Agent
Please help me install this Agent Skill.
Skill: zustand
Source: https://github.com/SmallAi-API/smaihub/tree/main/.agents/skills/zustand
Command: npx skills add https://github.com/SmallAi-API/smaihub --skill zustand-smallai-api

SYSTEM DOCUMENTATION & REQUIREMENTS

💡 This Skill includes references (resource) components.

What problem does it solve? Designing Zustand stores for a large TypeScript application often leads to inconsistent state shapes, tangled actions, and broken optimistic updates. This Skill encodes the LobeChat conventions for structuring stores so state stays predictable, cacheable, and type-safe. ## Core Features & Use Cases - State Shape Design: Separate lightweight list-item types from heavy detail types, use arrays for lists and id-keyed maps for cached details with per-item loading states. - Action Hierarchy: Enforces a three-layer action model of public actions, internal_* business logic, and internal_dispatch* reducer calls, plus guidance on when to use a reducer versus a simple set. - Optimistic Updates & Class-Based Slices: Provides the standard optimistic update flow (dispatch, service call, refresh) and the migration pattern from plain StateCreator objects to class-based actions composed with flattenActions. - Use Case: When adding a new entity store (e.g., a benchmark evaluation store), follow the references to define Detail/ListItem types, a detail map with a typed reducer, SWR-based fetching, and selectors. ## Quick Start Use the zustand skill to design a new store slice for my entity with list and detail state, optimistic updates, and class-based actions.

Frequently Asked Questions about zustand

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I structure a Zustand store with slices in TypeScript?

Create one directory per slice containing initialState.ts, action.ts, selectors.ts, and optionally reducer.ts. Aggregate slice states in a top-level initialState.ts and combine slice actions in store.ts using a StateCreator that spreads initialState and each slice creator.

How to implement optimistic updates in Zustand?

Dispatch a local reducer action with a temporary id first, then call the backend service, then refresh from the server for consistency. Delete operations should skip optimistic updates because recovery is complex; use per-item loading flags instead.

When should I use a reducer versus a simple set in Zustand?

Use a reducer when managing object lists or maps, performing optimistic updates, or handling complex state transitions. Use a simple set call for toggling booleans, updating single fields, or setting simple values.

Should list and detail types be separate in a Zustand store?

Yes. Keep a lightweight ListItem type that excludes heavy fields like content or rubrics, and never extend the Detail type. Store lists as arrays and cache details in a Record<string, Detail> map with per-item loading ids.

How do I compose class-based actions in a Zustand slice?

Define a class receiving (set, get, api) in its constructor with #private fields, then merge instances in the store creator using flattenActions rather than spreading. Export a Pick-based type to expose only public methods.

Why should store types come from a shared types package instead of the database package?

Store types should be imported from @lobechat/types rather than @lobechat/database to keep client state decoupled from database schemas. This prevents heavy database fields from leaking into list rendering and keeps type boundaries clean.