用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/Dev-Toolbelt/dev-team-agents --skill state-management命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | state-management |
| description | Frontend state — where it lives, library selection, architecture. |
Apply this hierarchy before reaching for a library:
Is the state used by only one component?
└─ Yes → useState / ref / signal (local state)
Is the state shared between a parent and a few children?
└─ Yes → lift to the nearest common ancestor (prop drilling is fine up to 2 levels)
Is the state shared across distant components in the same feature?
└─ Yes → Context / provide-inject / feature-scoped store
Is the state global app state (auth, theme, cart)?
└─ Yes → global store (Zustand, Pinia, NgRx, etc.)
Is the state data fetched from a server?
└─ Yes → server state library (TanStack Query, SWR, Apollo, RTK Query)
NOT a global store — server state has its own lifecycle
The most common mistake: putting server data in a global store and manually managing loading/error/stale states. Let the server state library own it.
Server state (data that lives on a backend) must be managed by a dedicated library (TanStack Query, SWR, Apollo, RTK Query). Never copy it into a useState or store slice — it creates synchronization bugs and stale data.
If a value can be computed from existing state, compute it — don't store it separately.
// bad — selectedCount gets out of sync
const [items, setItems] = useState([])
const [selectedCount, setSelectedCount] = useState(0)
// good — derived on render, always accurate
const selectedCount = items.filter(i => i.selected).length
Global state has a maintenance cost. Resist the pull to globalize everything. Promote state up the tree only when a second consumer appears (YAGNI).
Never mutate state directly. Always produce a new reference. This enables reliable change detection in every framework.
State changes must go through a defined action, mutation, or setter — not direct property assignment from outside the store. This makes state changes traceable and debuggable.
useCartStore, useAuthStore) — not one mega storesubscribeWithSelector for derived state that depends on a slice of the storecart.ts → useCartStore)$patch for batch updates; avoid multiple $state mutations in sequencekeepAlive).value directlycreateFeatureSelector + createSelector for memoized derived statecreateSlice — never write reducers manuallycreateAsyncThunk for async operations; createApi (RTK Query) for server statecreateEntityAdapter| Anti-Pattern | Problem |
|---|---|
| Copying server response into a store slice | Duplicates state, creates staleness bugs |
| Storing derived values alongside source values | Source and derived drift out of sync |
| One global store for everything | Unrelated components re-render on unrelated changes |
Direct state mutation (state.count++) | Breaks change detection in every framework |
Reading store state inside useEffect dependencies | Creates infinite loops or stale closures |
| Async logic inside a reducer | Reducers must be pure; side effects belong in actions/effects/thunks |