# @forge-go/client-react 中文文档

规范地址：https://npmcn.com/package/%40forge-go/client-react/

版本：1\.13\.7
npm 元数据更新时间：2026-11-12T01:10:36.559Z
中文译文更新时间：2026-11-15T07:33:45.245Z
软件包许可：MIT

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

原始 npm 页面：https://www.npmjs.com/package/%40forge-go/client-react
原文对照：https://npmcn.com/package/%40forge-go/client-react/?lang=original
项目主页：https://github.com/xraph/forge/tree/main/packages/client-react#readme
源码仓库：https://github.com/xraph/forge

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

- 包体积（解压后）：101 kB，32 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：0 个
- peer 依赖：react ^18\.0\.0 \|\| ^19\.0\.0，@forge-go/client-core ^1\.13\.7
- 首次发布：2026-08-07T04:05:16.201Z
- 最新版本发布：2026-11-12T01:10:36.256Z
- 近 30 天下载量：2600（2026-10-16 至 2026-11-14，npm 官方下载统计）
- 已发布版本数：25（近 12 个月 25 个）

## 中文简介

对 Forge 客户端运行时间的回放绑定: 使用SyncExternalStore 来覆盖已规范的查询缓存

## 安装

```sh
npm install @forge-go/client-react
```

也可以使用：`pnpm add @forge-go/client-react`、`yarn add @forge-go/client-react`、`bun add @forge-go/client-react`

## README

# @ forge-go/ 客户端反应

反应绑定 [`@forge-go/client-core`](https://npmcn.com/package/%40forge-go/client-core)三根钩子和一个 提供商, 1.07 kB gzipped.

一切决定 _什麽_ 价值是——身份、僵硬、分化, 无效性——是在核心中决定的,在没有渲染器的情况下可以测试. 剩下的是满足的狭隘工作 `useSyncExternalStore`是因为 合同没有取消任何合同.

```tsx
import { useQuery, useMutation } from '@forge-go/client-react';
import { useOrderList, useOrderCreate } from './generated/hooks';

function Orders() {
  const { data, status, error, isFetching, refetch } = useQuery(useOrderList, {
    query: { status: 'open' },
  });
  const create = useMutation(useOrderCreate);

  if (status === 'pending') return <Spinner />;

  return (
    <>
      <button disabled={create.isPending} onClick={() => create.mutate({ body: { total: 0 } })}>
        New order
      </button>
      {create.status === 'error' && <Warning error={create.error} />}
      <ul>{data?.map((order) => <Row key={order.id} order={order} />)}</ul>
    </>
  );
}
```

`mutate` **从不拒绝**: 失败 `status` 财务报告和审定财务报表 `error`,则 承诺解决 `undefined`这是故意的, 这就是为什么处理者 上面需要没有 `.catch`。记录错误的突变 _财务报告和审定财务报表_ 拒绝 请每个召唤者记取一个--每个被遗忘的-- `.catch` 是一个 `unhandledrejection` 每写作失败, 生产中意味着提示射击 关于用户已经查看的错误.

当您在写完之后需要按顺序工作时,如果没有,则不得继续工作 要求拒绝姓名:

```ts
await create.mutateAsync({ body: { total: 0 } }); // throws on failure
router.push('/orders');
```

两者记录相同状态. 唯一的区别是谁是失败的主人.

第一个参数是生成物的绑定 `hooks.ts` (单位:千美元)`export const useOrderList = query(ops.orderList)`),这是一个模块级 常数。 没有每个端点的钩子可以生成 也没有再生 当此软件包改变时.

## 配置客户端

`configureClient()` 从核心本身就够了:

```ts
import { configureClient, RestTransport } from '@forge-go/client-core';
import { entities } from './generated/ops';
import { client } from './generated/rest';

configureClient({ transport: new RestTransport({ client }), entities });
```

`ClientProvider` 实值 **选项**并故意这样做。 生成 `hooks.ts` (a) 早在应用程序存在之前就将任何东西交给模块范围; 要求提供者将意味着从 Go 路由表重生的文件 决定消费性应用如何进行依赖性注射。 打开一个 一个全局是错误的答案——服务器同时处理两个请求,a 测试,不能漏入下一个, 应用程序对两个 后端 :

```tsx
<ClientProvider client={cache}>
  <App />
</ClientProvider>
```

决议是明确的,然后提供,然后是全球性的: `useQuery(op, args, {client})` 击败供应商,击败 `configureClient`三个都没有, `getClient()` 扔出一个名称而不是刻出一个抓取缓存,什么也没有 别人也看得出来.

## 它的保证

-   **每个查询一个请求,而不是每个组件.** 两个部分呼叫 `useQuery(useOrderList)` 是一个缓存条目,一个注册挂载和一个 请求。 他们一起定居.
-   **写给 `Order:7` 只重写参考文献 `Order:7`。 。 。 .** 没有 无效在组件中被写入; 服务器已声明 .
-   **一个不变的实体在反射处保留其对象身份**,所以一个 `memo`'会排出它跳过。 集装箱没有保证:新鲜的 反应是一种新鲜的骨架,商店并不声称知道 列表的形状不变。 身份在身份已知的地方得到保障.
-   **严格模式的挂载 / 卸载 / 挂载 , 叶片完全是一个活订阅** 并且不会引起第二次请求——关于套接字和查询.
-   **`live` 每个呼叫站点都选择进入,并在下面共享.** 两个组件在 相同的实时查询是 1 订阅; 2 _不同_ 实时查询 使用同一通道的实体是一个连接.

## 刷新您不持有的查询

`useQuery` 手举起 `refetch` 用于打开该组件的查询。 当 写别的地方,使用 `useInvalidate`数字 :

```tsx
import { useInvalidate, useMutation } from '@forge-go/client-react';
import { useOrderArchive, useOrderList } from './generated/hooks';

function ArchiveDialog({ id, onDone }: { id: number; onDone: () => void }) {
  const archive = useMutation(useOrderArchive);
  const invalidate = useInvalidate();

  return (
    <button
      onClick={async () => {
        await archive.mutateAsync({ path: { id } });
        invalidate(useOrderList);
        onDone();
      }}
    >
      Archive
    </button>
  );
}
```

你给行动起名,从不给部件起名. `useOrderList` 是模块级 生成的常数 `hooks.ts`,所以对话框导入它想要的读取 清新和保持无知 任何列表 碰巧显示它.

三种说法:

```tsx
invalidate(useOrderList);                     // every cached variant
invalidate(useOrderGet, { path: { id: 7 } }); // that one exactly
invalidate.tags(['Order[]', 'Order:7']);      // the tag graph directly
```

不通过参数而覆盖每页,过滤并排序缓存所控 通常你的意思是,一旦一个字落地。 过 参数,你得到一个查询 他们按键,同一个键 `useQuery` 计算 当其他组件打开时。 一个皱纹. `invalidate(op)` 财务报告和审定财务报表 `invalidate(op, {})` 不为同一查询命名, 因为一个读取了没有 参数与空对象调用的参数不同 不争辩的表 覆盖两者.

`invalidate` 标记查询暂停和返回。 挂载在下一条 组合成一回合 请求。 卸载者保留旗子,在下次登上时进行反射,所以 在路径中列出您在返回之前 避免了成本成本 对它.

须等时取名相求:

```tsx
await archive.mutateAsync({ path: { id } });
await invalidate.refetch(useOrderList);
onDone();
```

火柴一解决就解决了 是一个对话框关闭之前想要的 . 它拒绝失败,像 `mutateAsync` 和与 `mutate`。未挂载匹配 保持懒惰。 查找二十个缓存过滤器组合 20项申请将毫无意义.

到达 `tags` 您的操作声明 `provides`这是 运行时间本身的模型, 它保留在服务器上的决定 其中的chema 活着 大部分生成的今天没有声明,所以可以调用的形式 按操作处理查询,并工作到标记图是否有边缘 来点新鲜的.

`useInvalidate(cache)` 使用相同的覆盖 `useClient` 夺去,并解决 同样的方式,没有了一个,所以你无效 通过你读到的缓存。 这个 只要缓存稳定,就可以放回去 或把它交给一个 `memo`'孩子'.

## 实时查询

```tsx
const { data } = useQuery(useOrderList, { query: { status: 'open' } }, { live: true });
```

它订阅每个频道的列表 绑定到这个查询的实体 结果类型可以包含,并在最后一个消费者卸载时释放出. A 类 框架直接更新存储, 所以 `order.updated` 没有要求.

**专访,每个呼叫网站,故意.** 自动就更少了 字符和两个更糟糕的属性: 开发者读取组件不能 更长的时间显示它是否持有套接字, 以及应用程序的连接数 将成为造物树的产物.

`live` 是一个普通道具,所以它可能会改变。 正在尝试订阅或发行 并且确实 **无** 至查询——无再挂载、无回移、无装入状态. 打开它并不能掩盖它关闭的窗口:新鲜是 缓存的业务,和 `live` 不是一个隐藏的还原触发器。 差距 真正的是运行时间的过错,一个被丢弃的套接字被核心回收.

它需要一个流跑时间——a `StreamBinder` 建在同一缓存上. 没有一个人, `{live: true}` 通过缓存报告 `onError` 而不是说 静悄悄地递回一个从未更新的查询 .

## 服务器渲染

```tsx
import { HydrationBoundary } from '@forge-go/client-react';

<HydrationBoundary state={state} ops={ops}>
  <OrderTable />
</HydrationBoundary>
```

`state` 这是什么 `dehydrate` 在服务器上生产 `ops` 是生成的 操作表直接通过. `hydrate` 需要它是因为缓存 记录有 `OperationMeta` 晚点再换一个.

**它在制成过程中而不是在作用中水合物.** 儿童阅读 `getSnapshot` 在它们自己做成的过程中, 发生在此组件之后 使返回,所以在第一次通过时,它们可以看到一个变相水合物. 在树下行走之后, 效果是: 第一个涂料是装入 分枝再翻 是一个明显的闪光 水合通道上, 完全匹配组件中要删除的 。 它不包含 由于包装会改变DOM 双方 正在比较中.

严格Mode双接力渲染,所以边界可以记起它的载荷 已经水合到缓存中 。 标记已经设定 _之后_ 水分 成功, 从未有过 : 重试一个抛出的渲染, 然后先标记 使孩子们成为 虽然它已经奏效.

`getServerSnapshot` 现在读取 `QueryCache.peek`,它返回什么 缓存保存时没有打开它从未见过的查询记录 。 这么说吧 `renderToString` 发出真正的标记,其中边界使缓存在 组件,以及 `idle` 在那里没有人这样做。 双方同意无论哪种方式,这就是 属性 反应实际检查.

拒绝有效载荷的处理方式是理性的,而不是电文。 校长 不匹配重推, 因此您的错误边界会抓住它 挂载。 通过缓存报告版本或操作不匹配 `onError` 和树使上, 因为两者都通过查询修复 仅仅为自己取取 并空白一页 通过每次部署 比问题更严重 任何无法识别的重播.

## 还没做什么

德发道具.

## 同伴依赖关系

两种反应 **财务报告和审定财务报表** `@forge-go/client-core` 是同龄人,而不是依赖关系。 两个 复制的 React 表示向错误的渲染器发送的钩子. 两份 核心表示两个模块级缓存,因此应用程序配置的客户端 它产生的钩子不是从同一个缺陷中读取的,而是从下面一层.

反应18和19都得到了支持和测试.

## 常见问题

### @forge-go/client-react 是什么？

对 Forge 客户端运行时间的回放绑定: 使用SyncExternalStore 来覆盖已规范的查询缓存

### 如何安装 @forge-go/client-react？

在项目目录运行 npm install @forge-go/client-react，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：react（^18\.0\.0 \|\| ^19\.0\.0）、@forge-go/client-core（^1\.13\.7）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @forge-go/client-react 支持 TypeScript 吗？

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

### @forge-go/client-react 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @forge-go/client-react 可以商用吗？

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

### @forge-go/client-react 的下载量有多少？

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

### @forge-go/client-react 还在维护吗？

最新版本 1\.13\.7 发布于 2026/11/12（3 天前）；至今共发布 25 个版本，其中过去 12 个月发布了 25 个；首次发布于 2026/08/07。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

