# @\_linked/react 中文文档

规范地址：https://npmcn.com/package/%40_linked/react/

版本：2\.1\.0
npm 元数据更新时间：2026-11-02T00:35:49.924Z
中文译文更新时间：2026-11-06T07:50:19.131Z
软件包许可：MIT

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

原始 npm 页面：https://www.npmjs.com/package/%40_linked/react
原文对照：https://npmcn.com/package/%40_linked/react/?lang=original
项目主页：https://github.com/linked-fw/react#readme
源码仓库：https://github.com/linked-fw/react

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

- 包体积（解压后）：230 kB，46 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：0 个
- peer 依赖：react ^18\.2\.0 \|\| ^19\.0\.0，react-native \>=0\.76，@\_linked/core ^2\.46\.0
- 首次发布：2026-02-12T04:31:53.565Z
- 最新版本发布：2026-11-02T00:35:49.523Z
- 近 30 天下载量：4076（2026-10-05 至 2026-11-03，npm 官方下载统计）
- 已发布版本数：40（近 12 个月 40 个）

## 中文简介

QQ链接/ 核心的反应绑定

## 安装

```sh
npm install @_linked/react
```

也可以使用：`pnpm add @_linked/react`、`yarn add @_linked/react`、`bun add @_linked/react`

## README

# 链接/反应

反应约束 `@_linked/core`。 。 。 .

`@_linked/react` 获取链接的查询 `@_linked/core`是因为 [Schema-Parameter化查询 DSL](https://npmcn.com/package/%40_linked/core/README.md#schema-parameterized-query-dsl) 并映射用于React组件的道具的顶级查询结果键.

> **查询API注释.** 查询以 `Shape.select(...)` 返回一个 `QueryBuilder`A级 `QueryBuilder` 实值 **懒惰** - 只有在你着火的时候 `await` 它或通过它 `linkedComponent` 编号 : `linkedSetComponent`旧的 `Shape.query(...)` 构建者名称已去; 使用 `.select(...)` 到处都是.

本套件提供:

-   `linkedComponent(...)` 财务报告和审定财务报表 `linkedSetComponent(...)` ——活性,有数据约束的组件
-   `useLinkedQuery(...)` 财务报告和审定财务报表 `useLinkedSetQuery(...)` 钩子在他们下面
-   `LinkedComponentClass`
-   `useStyles(...)`, (中文(简体) ), `useQueryContext(...)`

部件和钩子 **反应**:经过任何突变后——局部,由数据集的更改回馈报告,或由您代码发布——每个被挂载的元件,其查询可以读取已修改后的数据回溯和还原,其他都无所作为. 见 [反应](https://npmcn.com/package/%40_linked/react/#readme-reactivity)。 。 。 .

## 安装

```bash
npm install @_linked/react @_linked/core react react-dom
```

支持反应 18 (E)`^18.2.0`)和反应19(`^19.0.0`) (中文(简体) ).

## 原生反应

从 `@_linked/react/native` 子路径而不是根 :

```tsx
import {linkedComponent, linkedSetComponent, linkedShape} from '@_linked/react/native';
```

它输出的API与 `@_linked/react` (相同对象,不是副本). 导入它还设置 React 本地渲染默认值, 因为内置加载器和出错元素是 `<svg>` 元素,以及 React Industrial 上的崩溃:

-   `LinkedComponentDefaults.loader`数字 : `<ActivityIndicator testID="linked-loader" />`
-   `LinkedComponentDefaults.errorElement`数字 : `<Text testID="linked-error" accessibilityRole="alert">Failed to load</Text>`
-   `LinkedInfinityLoader` 做同样的 `ActivityIndicator`

它只在您的应用程序尚未设置时设置默认值. 实例道具和定义选项仍然与往常一样优先。 至少使用第一个子路径 `@_linked/react` 导入您的应用程序评分, 例如在 `App.tsx`。 。 。 .

`react-native` (单位:千美元)`>=0.76`)是一种可选的同伴依赖。 根条目从不导入它,所以网络应用不会安装它,也没有获得对等警告.

## 使用量

### 设置套件导出

```tsx
import {
  linkedComponent,
  linkedSetComponent,
  linkedShape,
} from '@_linked/react';
```

### `linkedComponent(...)`

`linkedComponent(...)` 用链接查询来包裹反应组件。 您通过一个以 `Shape.select(...)` ——归来 `QueryBuilder` 懒惰 包装器在时间点燃它 当你通过 `of={{id: ...}}`,包装器将准备的查询应用于该主题,并将查询结果键作为道具注入到您的组件中.

```tsx
const PersonCard = linkedComponent(
  Person.select((p) => p.name),
  ({name, source, _refresh}) => (
    <article>
      <h3>{name}</h3>
      <small>{source.id}</small>
      <button onClick={() => _refresh()}>Reload</button>
    </article>
  ),
);

// External API: pass `of` as a node reference (`{id: string}`), Shape, or QResult.
<PersonCard of={{id: 'https://example.org/p1'}} />;
```

包裹组件收到的道具 :

-   查询结果道具:查询结果的所有顶级密钥都成为了直接道具(例如: `name`) (中文(简体) ).
-   `source`: 输入的已解析形状实例 `of` 主题.
-   `_refresh(updatedProps?)`: 重运行查询 (`_refresh()`)或复出前补丁本地查询结果道具(`_refresh({...})`) (中文(简体) ).
-   `_refreshing`数字 : `true` 当一个反射器在飞行中, 并且当前的数据仍然被解析出来.
-   自定义道具:您通过到链接组件的任何附加道具都会作为正则转发.

定义选项( 第三个参数, 或配置对象的密钥) : `loader`, (中文(简体) ), `errorElement`, (中文(简体) ), `notFoundElement` (单主体查询回答时放弃) `null`;没有它,组件用空结果道具制造, `name` (查询模板的注册名称,默认为组件的函数名)和 `reactive` (单位:千美元)`false` 选择不自动调试的组件. `loader`, (中文(简体) ), `errorElement` 财务报告和审定财务报表 `notFoundElement` 也可以通过每个实例进行,并通过 `LinkedComponentDefaults`。 。 。 .

#### `_refresh(updatedProps?)` 链接组件

`_refresh` 注入包裹 `linkedComponent(...)` 提供功能.

-   `_refresh()` 重新运行查询,然后返回结果.
-   `_refresh(updatedProps)` 合并 `updatedProps` 输入当前结果,并立即返回(不先获取)。 编辑器生活在共享的活query缓存中,因此每个显示相同查询的组件都会看到;下回重写会覆盖它. 预装儿童(完整的结果通过) `of`编辑保留在该组件的局部,以及 `_refresh()` 让它自己去取.
-   `updatedProps` 仅用于查询结果键(例如 `name`, (中文(简体) ), `active` 从您的询问中, 父母不会通过普通的额外道具.

例用例:突变后乐观UI.

```tsx
const PersonCard = linkedComponent(
  Person.select((p) => [p.name, p.active]),
  ({id, name, active, _refresh, title}) => (
    <div>
      <h4>{title}</h4>
      <span>{name}</span>
      <button
        onClick={async () => {
          // Patch query-result keys immediately (name/active/id/etc.)
          _refresh({active: !active}); // optimistic local query-result update
          await saveActiveFlag(id, !active); // your write call
          _refresh(); // optional: sync with store response
          // Not for parent custom props like `title`; those come from parent rerender.
        }}
      >
        Toggle active
      </button>
    </div>
  ),
);
```

### `linkedSetComponent(...)`

使用 `linkedSetComponent(...)` 当您想要制作来源列表时.

### `linkedSetComponent(...)` (直接查询格式)

```tsx
const NameList = linkedSetComponent(
  Person.select((p) => p.name),
  ({linkedData}) => (
    <ul>
      {(linkedData || []).map((person) => (
        <li key={person.id}>{person.name}</li>
      ))}
    </ul>
  ),
);
```

### `linkedSetComponent(...)` (名称:数据正文格式)

```tsx
const personQuery = Person.select((p) => [p.name, p.hobby]);

const NameList = linkedSetComponent({persons: personQuery}, ({persons}) => (
  <ul>
    {persons.map((person) => (
      <li key={person.id}>{person.name}</li>
    ))}
  </ul>
));
```

两种格式都得到支持. 对于链接集包,外部 API 也是 `of` (可选). 内部变成 `sources` 用于包裹组件.

### 导出您的组件 `src/components/index.ts`

一个软件包向构建者提供其组件( Create Now 的拖放构建器) `src/components/index.ts`:按名称导出每个链接组件.

```ts
// src/components/index.ts
export {PersonCard} from './PersonCard.js';
export {NameList} from './NameList.js';
```

`linked build` 然后将软件包的组件索引写入 `lib/esm/data/components.ttl`旁边 `shapes.ttl`: 每个链接组件的导出名称、起始形状、查询形状和线条中的查询 格式 (单位:千美元)`QueryBuilder.toJSON()`作为犬科JSON。 发电机是 `componentIndexTurtle(packageName, exports)` 内 `@_linked/react/utils/componentIndex`。 。 。 .

-   由 : `linkedComponent` 或者说 `linkedSetComponent` 已索引; 其他的都是 被忽略 。 以几个名称导出的一个组件是用最小名称命名的一个条目.
-   定义时绑定的查询记录为: `.for(getQueryContext('user'))` 作为 上下文参考`{"@ctx":"user"}`, (中文(简体) ), `.for('<iri>')` 因为,IRI, `.for(null)` 作为 `nullSubject`在模块负载时设置的查询上下文(`setQueryContext` 模块顶级 指数进口)作为IRI记录解决.
-   查询不序列化的组件被忽略,构建会打印一个命名它的警告.
-   没有 `src/components/index.ts`没有文件. `src/data/components.ttl` 是保留名称: 写吧.

## 渲染寿命周期和装载状态

何时 `LinkedStorage` 已初始化,数据尚未预先装入 `of`数字 :

-   第一个渲染: 返回装入元素( 已建入 SVG) `.ld-loader`,或 `loader` 从实例、定义选项或 `LinkedComponentDefaults`) (中文(简体) ).
-   查询解析:组件以映射出查询结果道具重接.
-   调试( N)`_refresh()`,或变化后的自动数据):当前数据仍然提供 `_refreshing` 实值 `true` 直到反应到达.
-   `of` 更改: 如果该主题已缓存在活水库中, 它会立即生成, 否则加载元素会显示到加载为止 .
-   相同查询共享一个请求和一个缓存结果,各组成部分之间.

## 反应

两个组成部分,一个主题:

```tsx
const TeamMembers = linkedComponent(Team.select((t) => t.members.name), ({members}) => (
  <ul>{members.map((m) => <li key={m.id}>{m.name}</li>)}</ul>
));
const TeamHeader = linkedComponent(Team.select((t) => [t.name, t.members.size()]), ({name, members}) => (
  <h2>{name} ({members})</h2>
));

await Team.update({members: {add: [{id: personId}]}}).for({id: teamId});
// → TeamHeader and TeamMembers refetch and rerender. A PersonCard for someone else does not.
```

如何运作:核心维持一个活平仓(见核心) [生活厨房指南](https://github.com/linked-fw/core/blob/main/documentation/live-queries.md)) (中文(简体) ). 每个挂载的组件都是其查询模板的活实例;模板的依赖性——即它所读取的,它过滤的或种类,它所触及的形状——是从查询中计算一次. 每一次更改都与它写的东西和它所触及的节点正常化,而商店完全反射出可以受到影响的事例,通过节点ID可以分辨,在无法分辨的地方则在模板上宽.

更改源, 所有自动设置 :

-   **本地变异** ——每个 `await Shape.update/create/delete(...)` 在应用中, `exec(target)` 包含.
-   **数据集的更改种子** ——执行的数据集 `IDataset.subscribeChanges(listener)` 报告在别处(另一个客户端,服务器任务)所做的更改,作为突变的DSL-JSON及其结果,或者作为预计算效果.
-   **你自己的交通工具** —— 说 `publishChange({mutation, result})` 或者说 `publishChange({effects})` 从应用程序代码(从 `@_linked/react`) (中文(简体) ).
-   **手动** —— 说 `invalidate(Team)`, (中文(简体) ), `invalidate({id})`, (中文(简体) ), `invalidate(query)` 或者说 `_refresh()`。 。 。 .

一个组件可以选择退出 `{reactive: false}`;这适用于其查询模板,即使用该精确查询的每个组件或钩子。 部件和钩子在React BestMode下是安全的. 通过的结果对象 `of` 由预装的家长(`preloadFor`)并不单独订阅;它通过父母保持新鲜,父母的询问包括孩子的田地.

## 钩子

组件建立在两个钩子上,为组件形状不适合的大小写导出 : 一个组件中的几个查询,一个取决于本地状态的查询(一个搜索框,一个选定的标签),有条件的取取取,一个内线计数,或者没有的数据 `of` 主题.

```tsx
import {useLinkedQuery, useLinkedSetQuery} from '@_linked/react';

function TeamPage({teamId}: {teamId: string}) {
  const team = useLinkedQuery(Team.select((t) => [t.name, t.members.size()]), {id: teamId});
  const total = useLinkedQuery(Team.select().toCount());
  const [q, setQ] = useState('');
  const results = useLinkedSetQuery(
    Person.select((p) => p.name).where((p) => p.name.contains(q)).limit(20),
    undefined,
    {enabled: q.length > 1},
  );
  if (team.loading) return <Spinner />;
  // team.data.name, team.data.members, team.refreshing, team.notFound, team.refresh(), team.patch({...})
  // results.data, results.page.next() / previous() / set(i) / setLimit(n)
}
```

-   `useLinkedQuery(query, of?, options?)` → `{data, loading, refreshing, error, notFound, refresh, patch}`。 。 。 . `of` 实值 `{id}`,形状,或结果对象;在构建者已经绑定时可选(`.for(id)`, (中文(简体) ), `.for(getQueryContext('user'))`)或是一个计数/任务. `loading` 表示还没有数据; `refreshing` 表示有数据存在,获取正在飞行中.
-   `useLinkedSetQuery(query, of?, options?)` - 同样的加法 `page: {next, previous, set, setLimit, index, limit}`。 。 。 . `of` 是一个 `ShapeSet` 或数组 `{id}`/形状/结果对象.
-   选项 : `enabled` (默认) `true`, (中文(简体) ), `reactive`, (中文(简体) ), `name`。 。 。 .

`getLiveQueryStore().templates()` 列出每个已注册的查询模板(组成部分在定义中登记其内容),以及 `getLiveQueryStore().prepare()` 急切计算它们的依赖性——一个app可以点火的查询列表,以便数据库调用.

### 钩子还是组件?

反应方式是相同的:挂起的钩子和挂起的组件都记录他们的查询的活实例,在匹配变化后,两者都进行回溯. 区别在于 **不渲染而发现**,其中只有链接的组件提供:

-   **`preloadFor(Component)`** - 父母读取孩子的静态 `query` 并在同一请求中加载其字段.
-   **包登记** ——构件按外形登记.
-   **模板登记册** ——其查询模板被固定在定义上,所以 `templates()` 编号 : `prepare()` 从应用程序开始列出它。 赤钩子的模板仅在挂载时列出,闲用时会被丢出.

使用 `linkedComponent` 编号 : `linkedSetComponent` 默认: 一个组件, 一个查询, 一个主题通过 `of`. 当形状不合适时到达钩子——一个组件中的若干查询,这个查询取决于当地状态,有条件取取取(`enabled`),一个内行计数或存在检查,数据没有 `of` 主体,或包接按自身条件构成的第三方组件。 基于钩的组件无法发现: 它没有静态 `query`,所以它不能是一个 `preloadFor` 目标,不在软件包登记册中,不能通过列出组件和它们需要的数据的工具提供可连接组件。 任何应该可以发现的东西——一个查询,一个主题通过 `of` 属于 `linkedComponent`。 。 。 .

## 在外边订阅 React

同一商店的工作没有反应: `query.live()` 返回控点为 `state`, (中文(简体) ), `subscribe(cb)`, (中文(简体) ), `refresh()`, (中文(简体) ), `patch()` 财务报告和审定财务报表 `close()`,以及 `await live` 以第一个结果解决。 见核心 [生活厨房指南](https://github.com/linked-fw/core/blob/main/documentation/live-queries.md)。 。 。 .

## 已链接的集页码 API

何时 `linkedSetComponent(...)` 有限制(明确查询限制或默认限制),包裹道具包括:

-   `query.nextPage()`
-   `query.previousPage()`
-   `query.setPage(pageIndex)`
-   `query.setLimit(limit)` (也移回第一页)

没有公众 `setOffset(...)` 在反应查询控制器中; 使用 `setPage`, (中文(简体) ), `nextPage`,或 `previousPage`。 。 。 .

示例

```tsx
import React from 'react';

const PeopleList = linkedSetComponent(
  Person.select((p) => [p.name]).limit(5),
  ({linkedData = [], query}) => {
    const [page, setPage] = React.useState(0);

    return (
      <section>
        <ul>
          {linkedData.map((person) => (
            <li key={person.id}>{person.name}</li>
          ))}
        </ul>

        <div>
          <button
            onClick={() => {
              query?.previousPage();
              setPage((p) => Math.max(0, p - 1));
            }}
          >
            Previous
          </button>

          <span>Page {page + 1}</span>

          <button
            onClick={() => {
              query?.nextPage();
              setPage((p) => p + 1);
            }}
          >
            Next
          </button>

          <label>
            Page size
            <select
              defaultValue="5"
              onChange={(e) => {
                const nextLimit = Number(e.target.value);
                query?.setLimit(nextLimit);
                query?.setPage(0);
                setPage(0);
              }}
            >
              <option value="5">5</option>
              <option value="10">10</option>
              <option value="25">25</option>
            </select>
          </label>
        </div>
      </section>
    );
  },
);
```

## 页:1

-   此软件包取决于 `@_linked/core` 查询 APIs 、 其活的- query 商店以及 `preloadFor(...)` 编号 : `BoundComponent` 行为从核心.
-   `@_linked/react` 本身不提供 RDF 存储; 使用存储包并设置默认存储 `LinkedStorage` (例如 `@_linked/rdf-mem-store`) (中文(简体) ).

## 存储设置( 例如 : `@_linked/rdf-mem-store`(中文(简体) )

本地内存设置, 请注册 `@_linked/rdf-mem-store` 作为默认存储 :

```tsx
import {LinkedStorage} from '@_linked/core';
import {InMemoryStore} from '@_linked/rdf-mem-store';

LinkedStorage.setDefaultStore(new InMemoryStore());
```

## 开始

-   添加 `setOffset` 改为 `linkedSetComponent` 查询控制器.

## 发展

```bash
npm run build
npm test
```

## 更改日志

见 [变动情况](https://npmcn.com/package/%40_linked/react/CHANGELOG.md)。 。 。 .

## 常见问题

### @\_linked/react 是什么？

QQ链接/ 核心的反应绑定

### 如何安装 @\_linked/react？

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

### @\_linked/react 支持 TypeScript 吗？

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

### @\_linked/react 支持 ESM 还是 CommonJS？

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

### @\_linked/react 可以商用吗？

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

### @\_linked/react 的下载量有多少？

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

### @\_linked/react 还在维护吗？

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

