# 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((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.