Agent skill · software engineering · lobehub
zustand
Use for Zustand stores: state shapes and type sources, state-only stores with xActions classes, replica-backed list/detail data (@lobechat/replica), selectors, optimistic writes, and legacy slice/internal_* action composition.
Why this skill is useful
Provides specific conventions and patterns for Zustand state management that the AI wouldn't reliably generate on its own.
What it needs
About 3k tokens when loaded. Last updated 2026-08-07. 81,352 stars on the source repository.
What this skill does
LobeHub Zustand State Management State Shapes and Types Import shared store types from @lobechat/types, not @lobechat/database. Keep lightweight list-item types separate from full detail types; list types must not extend heavy detail types. Key cached details by id (xxxDetailMap: Record<string, Detail>); never hold a single currentDetail object. Read through xxxSelectors aggregates (selectors.ts), not ad-hoc lambdas repeated across components. Before choosing list/detail shapes or type sources, read Data structures. State-Only Stores (default for new and migrated stores) Actions stay out of the Zustand state. Reference: src/store/page. File Owns ------------------ ------------------------------------------------------------------------------------------------------------------------ store.ts useXStore = createWithEqualityFn<XState>()(devtools(() => initialState), shallow): state only, no methods privateAction.ts XPrivateAction: replica slices, entity links, and write helpers shared by public actions. Not exported from index.ts action.ts XActionImpl (the public API) and the singleton xActions = new XActionImpl(setState, getState, new XPrivateAction(…)) Components read state with useXStore(selector) and call xActions.foo() directly. Never select an action out of the store. Sync hooks live on the public class and are called as xActions.useFetchX(params). Public actions call each other through this.foo(). Private helpers are reached through this.#private. Do not add internal methods to the store to share logic between classes. Label every write: this.#set(partial, false, n('actionName')) with const n = setNamespace('x'). Put reset() on the public class and register xActions in resetableActions in src/store/utils/userDataStores.ts. Tests drive xActions and assert on useXStore.getState(). To mock in component tests: vi.mock('@/store/x', () => ({ xActions: { foo: vi.fn() }, useXStore: … })). …
How to use it
Reference it in AdaL, Claude Code, Cursor or any coding agent — nothing to install:
@skills lobehub/zustand