@comwit/state

中文文档
2.7.0发布于 2026/11/08MITTypeScriptESM + CJS近 30 天下载 2089

反应状态管理以进行氛围编码 。 少取相记. 建造于克洛德代码.

中文使用文档
文档目录12 节
  1. 为什么是傻瓜?
  2. 安装
  3. 与人工智能特工合作
  4. 快开始
  5. 超越客户端状态
  6. 查询和下一个.js
  7. 从列表项目中获取细节
  8. 缓慢的初始装入
  9. URL 状态
  10. 文档
  11. 从 comwit
  12. 许可证

@ comwit/ 状态

反应状态为你和你的经纪人.

React and Next.js的州管理层,公布于 @comwit/state保持客户状态, 服务器查询,和一个域中的动作,然后通过一个打入的钩子使用.

网站 • 妇女 文档 • 妇女 快速启动 • 妇女 无

用于1 000多个项目 (原始内容存档于2013-10-12). comwit.io,一个克洛德代码动力的氛围编码平台 从韩国。 发起人: 伯尔。 。 。 .

为什么是傻瓜?

  • 一域一钩. 定义一个模型,添加动作,并将其与 create()。 。 。 .
  • 客户端状态和服务器数据在一起. 反应值、缓存查询和服务器水合 共享同一个域.
  • 行动内部有直接突变. 以普通 JavaScript 更新状态; 组件订阅 通过选择器.
  • 为编码代理所建. 紧凑 llms.txt 盖被子, 域结构,以及核心 API.

安装

npm install @comwit/state

支助 反应 18和19。对于下一个.js,跟着 应用路由器设置。 。 。 .

与人工智能特工合作

给Claude代码或你的编码代理这个提示:

Set up @comwit/state in this project using https://library.comwit.io/state/llms.txt.
Follow its domain structure and state management patterns.

快开始

一个文件中的完整计数器 :

'use client'

import { action, ComwitProvider, create, model } from '@comwit/state'

type CounterState = { count: number }
type CounterActions = { increment(): void; reset(): void }

const counter = model<CounterState>({ count: 0 })

const counterActions = action<CounterActions>(({ state }) => {
  const m = state(counter)

  return {
    increment() {
      m.count += 1
    },
    reset() {
      m.count = 0
    },
  }
})

const useCounter = create<CounterState, CounterActions>(counter, {
  actions: [counterActions],
})

function Counter() {
  const { count, actions } = useCounter((s) => ({ count: s.count, actions: s.actions }))

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={actions.increment}>Add one</button>
      <button onClick={actions.reset}>Reset</button>
    </div>
  )
}

export default function App() {
  return (
    <ComwitProvider>
      <Counter />
    </ComwitProvider>
  )
}

每个 ComwitProvider 拥有它的状态,模型仅在访问时初始化. 随着应用程序的增长, 拆分模型、动作和钩入 域文件夹。 。 。 .

超越客户端状态

你需要的东西API / 指南
带有 SSR 和 Suspense 的渲染服务器数据.suspend(arg)
在浏览器中获取并缓存数据query() + 键 .load(arg)
无安全部门改革替代品 useServerInsertedHTMLuseDomain.hydrate(...)
在不请求API的情况下恢复精确的索引DB视图local() + 键 .restore(arg)
保留索引DB视图并重新验证服务器local.query() 编号 : local.infinite()
坚持浏览器自有偏好persist()
来自状态的衍生值computed()
撤销和重做状态更改$history
在动作中添加重试、 跳出或共享错误处理动作装饰器

查询和下一个.js

读取服务器数据 .suspend(arg) 在客户部分中,在内部 <Suspense>数字 :

'use client'

function ProductDetail({ id }: { id: string }) {
  const product = useProduct((s) => s.detail.suspend(id))
  return product.data ? <h1>{product.data.title}</h1> : null
}
<Suspense fallback={<ProductSkeleton />}>
  <ProductDetail id={id} />
</Suspense>

下一个通过 js useServerInsertedHTML 给提供商一次。 服务器渲染运行 queryFn 财务报告和审定财务报表 将结果流入浏览器缓存中,所以水合使得它没有第二次请求. 那边 没有服务器组件获取,也没有路由适配器.

'use client'

import { useServerInsertedHTML } from 'next/navigation'

<ComwitProvider useServerInsertedHTML={useServerInsertedHTML}>{children}</ComwitProvider>

queryFn 运行在服务器和浏览器上,所以给一个具有绝对URL的API打电话,并返回JSON数据.

使用 .load(arg) 当组件成为自己的装入状态时。 报告 isLoading 期间 承诺后提出并开始请求,在安全部门改革期间从未:

const list = useProduct((s) => s.list.load({ page }))
if (list.isLoading) return <Skeleton />

没有读取查询状态 .load() 或者说 .suspend() 不启动请求.

在一个提供者没有 useServerInsertedHTML (或等同),服务器响应 无法到达客户端缓存,所以客户端导航再次请求它. 在服务器上获取 将结果传递给 useProduct.hydrate({ detail: { arg: id, data: initialProduct } }) 在此之前 域钩读取. 下一个J不需要这个 见 Next.js 向导。 。 。 .

从列表项目中获取细节

从列表中打开的细节可以同时从列表项目中画出,并在后面填入剩下的 承诺 宣布种子形状为 query() 从模型中推导出来 与 seed; 不变 .suspend(id) 然后直接访问(中止、流出)和适用 导航( 涂抹种子, 背景升级):

const catalog = model({
  list: query<ProductSummary[]>({ initialData: [], queryFn: api.product.list }),
  detail: query<ProductDetail | null, string, ProductSummary>({
    initialData: null,
    queryFn: (id) => api.product.find(id),
    seed: (id, { state }) => state.list.data.find((item) => item.id === id),
  }),
})
const detail = useCatalog((s) => s.detail.suspend(id))
if (!detail.data) return <ProductNotFound />
if (detail.isPartial) return <Product summary={detail.data} /> // detail-only fields are optional
return <Product summary={detail.data} reviews={detail.data.reviews} />

其结果是,工会受到歧视 isPartial当钥匙显示它的种子时, data 实值 ProductSummary & Partial<ProductDetail>, (中文(简体) ), isPartial 实值 true, (中文(简体) ), isLoading编号 :isSuccess 为: false,以及 isFetching 实值 true 直到升级结束 完全结果(isPartial: false(中文(简体) ) 已经 data: ProductDetail | null。没有种子的查询保留其现有的结果类型.

规则:

  • seed 在渲染过程中运行, 所以它必须是纯的: 读 state (模型本身的状态,只读) 快照,别写 返回时 null编号 :undefined 当模型没有钥匙时. state 输入 any 因为 query() 在模型存在前宣布 上下文参数为 QuerySeedContext<CatalogState> 输入它.
  • TSeed 可能只命名全部值的字段,类型相同;额外密钥是类型错误.
  • 带着种子, .suspend(id) 不暂停和 .load(id) 不报告 isLoading; 两者 画出种子并在承诺后开始升级。 既无种子又无缓存, .suspend(id) 和以前一样暂停和流出.
  • 一个完全的结果是,钥匙总是胜过它的种子,它永远不会降级, .set(), (中文(简体) ), hydrate() 和流式服务器结果都是完整结果.
  • staleTime 在键为部分时被忽略:升级总是运行.
  • 升级被拒绝:种子保留, isError: true, (中文(简体) ), isPartial: true (单位:千美元)refetch() 重审). 升级到 null数字 : data === null, (中文(简体) ), isPartial: false,所以一个 !data 分支生成 还没找到.
  • 种子为一键. 更改参数从不显示另一个密钥的种子, 并挂载多个 读者每人画自己的钥匙.

local.query() 一样 seed 通过同一第三种通用。 当地资源与 .load(id) (单位:千美元)local() 与 .restore(id)(三); .suspend() 无法在其上找到, 因为类型错误 并且作为无型号呼叫器的抛出错误,因为暂停会绕过持久恢复. 带着种子, .load(id) 以同步方式绘出isPartial: true永远 isLoading页:1 为密钥所存储的索引DB视图,然后将其替换为一个完整的值(isPartial: false一样 hydrate()),网络重新验证每 staleTime。没有存储的行,种子将保留 直到网络结果。 此提供者中已经恢复的密钥永远不会再次显示其种子 .

阅读另一个模型(实验):种子背景也提供 read(model) 对于一个种子 源居于另一个域的模式 :

seed: (slug, { state, read }) =>
  state.list.data.find((p) => p.slug === slug) ??
  read(lounge)?.overview.data?.blogs.find((b) => b.slug === slug)

建议的设计保留每个资源一个模型(一个需要多个资源调用的页面) 所以,一个细节的种子来源 通常生活在自己的模型和 state 实值 够了. read 运行在渲染的时间, 并且从未初始化, 挂载或观察它的模式 给定: 除非有其他东西在提供者中注册该模型,否则返回 undefined 财务报告和审定财务报表 键入或暂停。 它返回相同的只读快照 state 是( 无) .load(),没有取来,写出掷出。 种子不订阅: 读取密钥时的当前快照, 因此以后对其它模型的更改不会重播 a 键已绘制.

seed 与 placeholderData: 占位符保留 另一个键 完全可见结果 新的密钥负载; 种子是 同样的钥匙 部分价值。 无限和实时资源 不要取一个种子.

缓慢的初始装入

设定 slowLoadingMs: 500 打开 query() 或者说 local.query() 读取 isSlowLoading 通过通常 查询状态。 现有的加载旗帜,请求,缓存新鲜度,以及数据发送都保持它们的时间安排. 新旗帜为快速完成和可用缓存数据而保持不实,成为持续状态的真面目 初始负载,并立即清除成功/错误。 不需要组件、效果或请求密钥. 见 查询指南 为了渲染, SSR,重试,清理,以及所支持的查询变体. 这是查询声明选项, 不是 模型/提供者默认或独立 local() 选项.

URL 状态

searchParam() 在模型中直接声明输入的 URL 备份字段。 读他们通过相同的 域名勾通,并通过动作更新它们.

npm install @comwit/[email protected]

见 URL 状态参考 对于分析,默认, 浏览器历史和服务器渲染.

文档

开始于 图书馆. comwit.io。 。 。 .

从 comwit

自 v 2. . 0. 0 起, 包被命名为 @comwit/state。替换依赖性并更新进口:

- import { model, action } from 'comwit'
+ import { model, action } from '@comwit/state'

重命名没有更改 API 。 堕落者 comwit 包再导出 @comwit/state 页:1 兼容性。 见 v 2.0.0 移徙说明。 。 。 .

许可证

麻省理工学院

版本与发布记录

@comwit/state 共发布 29 个版本,首次发布于 2026/07/03;过去 12 个月发布了 29 个版本。

版本发布日期距今
2.7.0latest2026/11/086 天前
2.7.0-beta.02026/11/086 天前
2.6.02026/11/076 天前
2.6.0-beta.12026/11/076 天前
2.6.0-beta.02026/11/077 天前
2.5.22026/10/3015 天前

关于 @comwit/state 的常见问题

@comwit/state 是什么?

反应状态管理以进行氛围编码 。 少取相记. 建造于克洛德代码.

如何安装 @comwit/state?

在项目目录运行 npm install @comwit/state,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(^18.0.0 || ^19.0.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@comwit/state 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@comwit/state 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@comwit/state 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=18。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@comwit/state 可以商用吗?

@comwit/state 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@comwit/state 的下载量有多少?

根据 npm 官方下载统计,@comwit/state 在 2026/10/11 – 2026/11/09 这 30 天内被下载 2,089 次,日均约 70 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@comwit/state 还在维护吗?

最新版本 2.7.0 发布于 2026/11/08(6 天前);至今共发布 29 个版本,其中过去 12 个月发布了 29 个;首次发布于 2026/07/03。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。