# @comwit/state 中文文档

规范地址：https://npmcn.com/package/%40comwit/state/

版本：2\.7\.0
npm 元数据更新时间：2026-11-08T00:09:38.896Z
中文译文更新时间：2026-11-14T09:46:59.678Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40comwit/state
原文对照：https://npmcn.com/package/%40comwit/state/?lang=original
项目主页：https://library.comwit.io/state
源码仓库：https://github.com/comwit/state

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：347 kB，45 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- Node.js 要求：\>=18
- 运行依赖：1 个
- peer 依赖：react ^18\.0\.0 \|\| ^19\.0\.0
- 首次发布：2026-07-03T10:52:37.252Z
- 最新版本发布：2026-11-08T00:09:38.747Z
- 近 30 天下载量：2089（2026-10-11 至 2026-11-09，npm 官方下载统计）
- 已发布版本数：29（近 12 个月 29 个）

## 中文简介

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

## 安装

```sh
npm install @comwit/state
```

也可以使用：`pnpm add @comwit/state`、`yarn add @comwit/state`、`bun add @comwit/state`

## README

# @ comwit/ 状态

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

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

[网站](https://library.comwit.io/) • 妇女 [文档](https://library.comwit.io/state/docs) • 妇女 [快速启动](https://library.comwit.io/state/docs/guide/quickstart) • 妇女 [无](https://www.npmjs.com/package/@comwit/state)

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

## 为什么是傻瓜?

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

## 安装

```bash
npm install @comwit/state
```

支助 **反应 18和19**。对于下一个.js,跟着 [应用路由器设置](https://library.comwit.io/state/docs/guide/quickstart)。 。 。 .

### 与人工智能特工合作

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

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

## 快开始

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

```tsx
'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` 拥有它的状态,模型仅在访问时初始化. 随着应用程序的增长, 拆分模型、动作和钩入 [域文件夹](https://library.comwit.io/state/docs/guide/structure)。 。 。 .

## 超越客户端状态

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

### 查询和下一个.js

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

```tsx
'use client'

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

```tsx
<Suspense fallback={<ProductSkeleton />}>
  <ProductDetail id={id} />
</Suspense>
```

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

```tsx
'use client'

import { useServerInsertedHTML } from 'next/navigation'

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

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

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

```tsx
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 向导](https://library.comwit.io/state/docs/guide/nextjs)。 。 。 .

### 从列表项目中获取细节

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

```ts
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),
  }),
})
```

```tsx
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)` 对于一个种子 源居于另一个域的模式 :

```ts
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` 通过通常 查询状态。 现有的加载旗帜,请求,缓存新鲜度,以及数据发送都保持它们的时间安排. 新旗帜为快速完成和可用缓存数据而保持不实,成为持续状态的真面目 初始负载,并立即清除成功/错误。 不需要组件、效果或请求密钥. 见 [查询指南](https://library.comwit.io/state/docs/api/query#slow-initial-loading) 为了渲染, SSR,重试,清理,以及所支持的查询变体. 这是查询声明选项, 不是 模型/提供者默认或独立 `local()` 选项.

### URL 状态

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

```bash
npm install @comwit/state@2.4.0
```

见 [URL 状态参考](https://library.comwit.io/state/docs/api/router) 对于分析,默认, 浏览器历史和服务器渲染.

## 文档

开始于 **[图书馆. comwit.io](https://library.comwit.io/)**。 。 。 .

-   [快速启动](https://library.comwit.io/state/docs/guide/quickstart) 安装、提供商和您的第一个域.
-   [项目结构](https://library.comwit.io/state/docs/guide/structure) ——按域组织成长应用.
-   [AI 代理设置](https://library.comwit.io/state/docs/llm-setup) 使用紧凑指南和详细参考资料.
-   [发布注释](https://library.comwit.io/blog) 变化和移徙指南.

## 从 `comwit`

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

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

重命名没有更改 API 。 堕落者 `comwit` 包再导出 `@comwit/state` 页:1 兼容性。 见 [v 2.0.0 移徙说明](https://library.comwit.io/blog/v2.0.0-release)。 。 。 .

## 许可证

[麻省理工学院](https://npmcn.com/package/%40comwit/state/LICENSE)

## 常见问题

### @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 和提交记录判断。

