Files
store_ai_front/.trellis/spec/frontend/state-management.md
2026-05-07 16:14:31 +08:00

102 lines
4.1 KiB
Markdown

# State Management
> This document outlines the strategy and standards for managing state within this project, ensuring data flows predictably and efficiently.
---
## Overview
We follow a tiered state management strategy. Decisions on where to store state are based on the **scope of the data** and the **nesting depth** of the components that require it.
---
## State Categories & Selection Criteria
### 1. Local State (`useState`)
- **When to use**: When the state is only used within a single component or passed down to immediate children via props.
- **Scope**: Private to the component or its direct sub-tree.
### 2. Module/Scoped State (`Context API`)
- **When to use**: When state needs to be accessed by deeply nested components (e.g., Grandparent to Grandchild) within a **single functional module**, but is not needed globally.
- **Scope**: Specific to a feature folder or a logical module.
### 3. Global State (`Zustand`)
- **When to use**: When data needs to be shared across **multiple independent modules** or throughout the entire application (e.g., User Auth, Theme, Global Settings).
- **Scope**: Application-wide.
---
## Persistence Strategy
To ensure a seamless user experience, we distinguish between data that should survive a page refresh and data that is volatile.
### 1. Persistent State (LocalStorage)
By default, global state that represents user progress or configuration should be synchronized with **LocalStorage**.
### 2. Volatile State (`temp.ts`)
For data that **should not be cached** (e.g., temporary UI toggles, scroll positions, transient navigation info), we use a dedicated store.
- **Action**: Create a `temp.ts` file in the store directory.
- **Usage**: All non-persistent data must reside here to avoid cluttering the browser's storage.
---
## Zustand Implementation Standards
When creating Zustand stores, follow the naming conventions for state and actions as shown below.
### Standard Pattern Example
```typescript
/**
* 临时状态存储接口,用于存放不需要持久化的数据
*/
interface TempStore {
/** 页面滚动条距离顶部的距离 */
scrollTop: number;
/** 当前路由的元信息(标题等) */
routeInfo: routeInfo;
/** 当前设备是否为移动端 */
mobile: boolean;
/** 修改滚动条位置 */
changeScroll: (value: number) => void;
/** 更新路由元信息 */
changeRouterInfo: (value: routeInfo) => void;
/** 设置移动端状态 */
setMobile: (value: boolean) => void;
}
const useTempStore = create<TempStore>((set) => ({
// 初始状态
scrollTop: 0,
routeInfo: {
title: '首页'
},
mobile: false,
// 方法实现
changeScroll: (value) => {
set(() => ({ scrollTop: value }));
},
changeRouterInfo: (value) => {
set(() => ({ routeInfo: value }));
},
setMobile: (data) => {
set(() => ({ mobile: data }));
}
}));
```
## Best Practices
- Derived State: Whenever possible, calculate values on-the-fly rather than storing them in the state (e.g., don't store isLoggedIn, store the token and derive isLoggedIn = !!token).
- Action Naming: Use clear verbs for actions:
- changeX: For updating numerical or incremental values.
- setX: For overwriting values or booleans.
- Selectors: Always use selectors when consuming Zustand stores to prevent unnecessary re-renders:
const scrollTop = useTempStore((state) => state.scrollTop);
- Context Cleanup: When using Context, ensure the Provider is wrapped at the lowest common ancestor to minimize the re-render scope.
- **Mandatory Documentation**: Every store interface and every single state/action property MUST have a JSDoc `/** */` comment written in **Chinese**.
## Common Mistakes
- **Missing Comments**: Defining a store or property without a `/** */` JSDoc comment.
- **Wrong Language**: Writing comments in English. **All code comments must be in Chinese.**
- **Globalizing everything**: Don't put state in Zustand just because it's "easier." If it's local to a form, use `useState`.
- **Direct State Mutation**: Never try to mutate the state directly. Always use the `set` function provided by the store.