跳到正文
cccskills
免费在 GitHub 公开中文介绍

zustand

本指南介绍 Zustand 状态类型、选择器和独立动作类的组织方式,并说明如何用 `local-replica` 管理服务端列表与详情、乐观更新及失败回滚;修改旧式 store 时也提供相应参考。

原文查看原文说明

Use for Zustand stores: state shapes and type sources, state-only stores with xActions classes, replica-backed list/detail data (local-replica), selectors, optimistic writes, and legacy slice/internal_* action composition.

lobehub/lobehub星标 83,510(GitHub 83,510 + cccskills 0)

实测评分 未实测

查看安装方法

适用场景

  • 设计 Zustand 状态与动作
  • 同步服务端列表和详情
  • 实现乐观更新与失败回滚
  • 修改使用旧式 slice 的 store

中文介绍

功能

本指南说明如何组织 Zustand store 的状态、类型、选择器和动作。新建或迁移 store 时,建议将状态保留在 store 中,并把动作放在专用类里。组件通过选择器读取状态,直接调用动作类。共享 store 类型从 @lobechat/types 导入,列表项类型与完整详情类型分开定义。

服务端列表和详情使用 local-replica 管理本地数据恢复、重新验证、分页、乐观更新及失败回滚,并隔离用户和工作区的数据范围。指南说明如何定义资源、绑定 replica 切片、通过选择器读取数据、在没有视图挂载时获取数据,以及通过 replica API 写入。对于仍采用 slice 或 internal_* 动作的旧式 store,也提供了对应的修改参考。

适用场景

创建或迁移 store、确定列表与详情类型、同步服务端数据或实现乐观更新时,可以参考本指南。修改已有旧式 store 时,也可据此判断应沿用哪套约定。

使用示例

  • “请为这个 Zustand store 设计状态与动作分离的结构。”
  • “请说明如何用 local-replica 读写列表数据。”
  • “修改这个旧式 slice store 时需要注意什么?”

注意事项

没有特别事项。

本介绍由 AI(OpenAI Codex)根据公开的 SKILL.md 撰写。准确的规格请查看下方原文。

文档检查

AI 根据 SKILL.md 的内容检查了需要注意的操作和使用前提。评分只依据实际运行的结果(实测对比)。

安全性发送数据、删除文件、执行命令等是否有说明
A良好要求通过 replica API 写入,并说明回滚和用户范围隔离。
安装难易度所需工具和 API 密钥是否少且有说明
B部分不足依赖 local-replica 和应用内库,但未提供安装步骤。

不计入评分。 由 AI(OpenAI Codex)于 2026年10月26日 评估。仅供参考,安装前请同时查看原文。

如果您认为评估有误,请申请复核

请写明哪一项有误以及原因。无需登录。我们会对照 SKILL.md 重新评估,并在此处更新结果。

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

包含的文件(5)

  • SKILL.md5.6 KB
  • references/data-structures.md3.1 KB
  • references/data-structures/reducer.md2.5 KB
  • references/data-structures/types.md2.5 KB
  • references/legacy-slices.md5.5 KB

SKILL.md(原文)

安装前可以查看交给 AI 代理的指令内容。

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.

FileOwns
store.tsuseXStore = createWithEqualityFn<XState>()(devtools(() => initialState), shallow): state only, no methods
privateAction.tsXPrivateAction: replica slices, entity links, and write helpers shared by public actions. Not exported from index.ts
action.tsXActionImpl (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: … })).

Replica-Backed Server Data

Server lists and details the UI paints go through @/libs/replica, not a hand-written SWR onSuccess + reducer. The engine owns hydration from IndexedDB, head revalidation, paging, optimistic overlays with rollback, and scope (user + workspace) isolation. API reference: the local-replica README. The engine is maintained in lobehub/local-replica: fix it there, publish, then bump the dependency here.

  1. Define the resource (defineReplica / definePagedReplica) in the store's projection.ts, converting server rows at the boundary.
  2. Add two state fields per replica: the view (xxxMap: Record<key, TData>) and its bookkeeping (xxxReplica: createReplicaState()).
  3. Bind it in the private class: createReplicaSlice(resource, { get, set, stateKey: 'xxxReplica', view: recordLens('xxxMap'), … }). When the same entity lives in several replicas (list row + detail), link them with linkReplicaEntity([list, detail]).
  4. Read: slice.useSync(params) returns only fetch flags (isHydrated, isValidating, error, revalidate). Data comes from selectors over xxxMap. "Entry is undefined" is the loading signal — do not add xxxInit flags or loadingXxxIds.
  5. Read with no view mounted (hover prefetch, refresh after a mutation): await slice.fetch(params) ({ fresh: true } after a write). Never call the service and slice.replace(...) by hand, because that skips the scope, removal, clear and superseded-request guards. Side effects of every response (not-found maps, seeding another store) go in the slice effects (onApplied / onMissing / onPurge / onError) with isMissing, not in one hook's onSuccess.
  6. Cold start without a skeleton: useSync hydrates only after the component mounts. For a list that must paint from the local copy, add a preHydrate action (ensureScope + hydrate) and call it from the route's loader through a lazy wrapper (src/spa/router/pageListLoader.ts, agentChatTopicListLoader.ts) bounded by settleWithin(…, PRE_PAINT_HYDRATE_TIMEOUT) from @/libs/replica/prePaint. @/libs/replica presets the cache scope, IndexedDB / localStorage storage (AppIndexedDBStorage / AppLocalStorage in @/libs/replica/storage) and the app's SWR driver; the package README stays app-agnostic.
  7. Write: slice.optimistic(key, apply, serverCall) or entity.optimistic(id, fn | 'remove', serverCall). A failed call rolls back to the confirmed value, so deletes are optimistic too. Rows that exist only on the client (temp ids) are declared with isClientOnly and seeded with update(key, fn, { persist: false }).

Outside test seeding, write a replica's view only through its slice. A plain set bypasses the engine's bookkeeping (persistence, rollback base, entity links).

Legacy Stores

Stores that still flatten action classes into state (flattenActions, create*Slice, internal_*, internal_dispatch* + reducers, SWR onSuccess syncing) follow Legacy slices. Use that layout only when editing one of those stores; migrate to the layouts above when moving its data onto a replica.

评价

还没有评价。欢迎分享你的使用感受。

评论

无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。

还没有评论。来写第一条吧。

提交后会立即公开。请勿填写邮箱、电话等个人信息。URL 最多 2 个。

0 / 1000 字

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

同一仓库的技能

acceptance

免费有简介

通过实际操作产品验证交付内容,记录用户可查看的证据,并发布验收报告。可检查已有验证计划或创建检查项,选择合适的操作界面,并使用 `lh` CLI 发布结果。

  • 实际检查更改后的产品行为
  • 收集截图或其他验证证据
  • 编写验证计划和报告
lobehub/lobehub8.4万2026年10月26日 更新

add-model-provider

免费有简介

本技能指导在 LobeHub 中接入 AI 模型提供商,涵盖运行时、模型信息、设置、品牌展示、文档和验收,并帮助判断新增模型是否需要新的提供商集成。

  • 为 LobeHub 接入新的 AI 模型提供商
  • 更新提供商设置说明或介绍
  • 判断添加模型是否需要新的提供商集成
lobehub/lobehub8.4万2026年10月26日 更新

add-setting-env

免费有简介

本技能指导如何用服务器端环境变量设置用户偏好默认值,涵盖变量校验、服务器配置、写入用户状态,以及更新 `.env.example` 和自托管文档。

  • 通过环境变量设置用户偏好默认值
  • 将设置接入服务器配置和用户状态
  • 更新环境变量示例及文档
lobehub/lobehub8.4万2026年10月26日 更新

agent-runtime-hooks

免费有简介

说明如何在智能体执行步骤、工具调用、人工审批、上下文压缩和子智能体调用时注册钩子。钩子可观察事件、模拟本地工具结果,也可通过 Webhook 按配置策略允许或拒绝工具调用。

  • 记录智能体步骤和错误
  • 测试时模拟工具结果
  • 通过 Webhook 允许或拒绝工具调用
lobehub/lobehub8.4万2026年10月26日 更新

agent-signal

免费有简介

此技能用于为智能体设计事件驱动的后台工作流,划分来源、信号、动作和策略的职责,并处理异步交接、去重、执行范围、完成记录与运行观测。

  • 添加事件触发的后台任务
  • 将工作移出对话请求
  • 防止动作重复执行
lobehub/lobehub8.4万2026年10月26日 更新

agent-testing-bot

免费有简介

本技能在 macOS 桌面聊天应用中测试机器人频道:打开应用、进入频道或联系人、发送消息、等待回复并截图。支持 Discord、Slack、Telegram、微信、飞书和 QQ;iMessage 使用 BlueBubbles 桥接。

  • 检查真实 Discord 频道中的机器人回复
  • 测试 Slack 或 Telegram 的对话流程
  • 记录 macOS 应用中的操作结果
lobehub/lobehub8.4万2026年10月26日 更新

查看 lobehub 的全部技能

报告此技能的问题