home / skills / lobehub / lobe-chat / zustand
This skill guides Zustand state management for store code, actions, and slices, improving state reliability and developer productivity.
npx playbooks add skill lobehub/lobe-chat --skill zustandReview the files below or copy the command above to add this skill to your agents.
---
name: zustand
description: Zustand state management guide. Use when working with store code (src/store/**), implementing actions, managing state, or creating slices. Triggers on Zustand store development, state management questions, or action implementation.
---
# LobeChat Zustand State Management
## Action Type Hierarchy
### 1. Public Actions
Main interfaces for UI components:
- Naming: Verb form (`createTopic`, `sendMessage`)
- Responsibilities: Parameter validation, flow orchestration
### 2. Internal Actions (`internal_*`)
Core business logic implementation:
- Naming: `internal_` prefix (`internal_createTopic`)
- Responsibilities: Optimistic updates, service calls, error handling
- Should not be called directly by UI
### 3. Dispatch Methods (`internal_dispatch*`)
State update handlers:
- Naming: `internal_dispatch` + entity (`internal_dispatchTopic`)
- Responsibilities: Calling reducers, updating store
## When to Use Reducer vs Simple `set`
**Use Reducer Pattern:**
- Managing object lists/maps (`messagesMap`, `topicMaps`)
- Optimistic updates
- Complex state transitions
**Use Simple `set`:**
- Toggling booleans
- Updating simple values
- Setting single state fields
## Optimistic Update Pattern
```typescript
internal_createTopic: async (params) => {
const tmpId = Date.now().toString();
// 1. Immediately update frontend (optimistic)
get().internal_dispatchTopic(
{ type: 'addTopic', value: { ...params, id: tmpId } },
'internal_createTopic'
);
// 2. Call backend service
const topicId = await topicService.createTopic(params);
// 3. Refresh for consistency
await get().refreshTopic();
return topicId;
},
```
**Delete operations**: Don't use optimistic updates (destructive, complex recovery)
## Naming Conventions
**Actions:**
- Public: `createTopic`, `sendMessage`
- Internal: `internal_createTopic`, `internal_updateMessageContent`
- Dispatch: `internal_dispatchTopic`
- Toggle: `internal_toggleMessageLoading`
**State:**
- ID arrays: `messageLoadingIds`, `topicEditingIds`
- Maps: `topicMaps`, `messagesMap`
- Active: `activeTopicId`
- Init flags: `topicsInit`
## Detailed Guides
- Action patterns: `references/action-patterns.md`
- Slice organization: `references/slice-organization.md`
This skill is a practical guide for implementing and maintaining Zustand stores in a TypeScript codebase. It focuses on clear action hierarchies, naming conventions, optimistic updates, and when to use reducers versus simple set operations. Use it to standardize state logic across store files and slices under src/store/**.
The guide defines three action layers: public actions for UI-facing flows, internal actions for core business logic and optimistic updates, and dispatch methods that perform reducers and direct state mutations. It explains patterns for optimistic creation, when to avoid optimistic deletes, and how to organize state as maps, ID arrays, and flags. Concrete naming rules and examples help you implement consistent, testable store code.
When should I prefer a reducer over a simple set call?
Use reducers for collections, maps, and complex transitions or optimistic flows. Use simple set for toggles or single-field updates.
Can I call internal_* actions from UI components?
No. Internal actions are meant for business logic and optimistic handling and should be invoked by public actions to keep validation and orchestration centralized.