docs(record): add bilingual usage guides

This commit is contained in:
Maofeng
2026-09-28 17:24:14 +08:00
parent d3de7cc172
commit 1353dc3145
9 changed files with 488 additions and 0 deletions
@@ -0,0 +1,62 @@
---
title: 嵌套上下文与稳定标识
description: 组合局部记录上下文,并为记录列表选择稳定的 React key。
order: 20
toc:
- id: nested-records
title: 嵌套记录
- id: optional-provider
title: 可选 Provider
- id: stable-keys
title: 稳定标识
---
## 嵌套记录 {#nested-records}
Provider 可以嵌套。内层字段读取局部记录,离开内层边界后恢复外层记录。
```tsx
<RecordProvider value={order}>
<OrderNumber />
<RecordProvider value={order.customer}>
<CustomerName />
</RecordProvider>
</RecordProvider>
```
不要把记录上下文当作可变 Store。新数据到达时,把新的记录引用传给 Provider;需要编辑的字段交给表单或其他状态层管理。
## 可选 Provider {#optional-provider}
`OptionalRecordProvider` 只在 `value` 不是 `undefined` 或 `null` 时创建新边界。值为空时,它保留最近的父级记录;`0`、`false` 和空字符串仍会创建新边界。这适合既能接收 prop、又能嵌入现有记录界面的组件。
```tsx
function ProductCard({ product }: { product?: Product }) {
return (
<OptionalRecordProvider value={product}>
<ProductTitle />
<ProductPrice />
</OptionalRecordProvider>
)
}
```
## 稳定标识 {#stable-keys}
`RecordsIterator` 会直接使用字符串、数字或 bigint 记录作为 key;对于对象记录,它默认读取 `id`。其他值或没有 `id` 的对象可通过回调提供 `recordKey`,对象也可以提供字段名。只有未获得有效标识时才会回退到数组下标。
```tsx
<RecordsIterator
data={locales}
iterator={(locale) => <LocaleRow />}
recordKey="code"
/>
<RecordsIterator
data={revisions}
recordKey={(revision) => `${revision.documentId}:${revision.version}`}
>
<RevisionRow />
</RecordsIterator>
```
@@ -0,0 +1,77 @@
---
title: 记录列表示例
description: 使用共享字段组件渲染带上下文的记录列表。
order: 30
toc:
- id: define-field-components
title: 定义字段组件
- id: render-the-list
title: 渲染列表
- id: iterator-callback
title: 使用迭代回调
- id: add-separators
title: 添加分隔内容
---
## 定义字段组件 {#define-field-components}
字段组件只依赖记录上下文,可以复用于详情页、列表和嵌套对象。
```tsx
function ProductName() {
const name = useFieldValue<Product, "name">({ source: "name" })
return <strong>{name}</strong>
}
function ProductPrice() {
const price = useFieldValue<Product, "price">({ source: "price" })
return <span>¥{price}</span>
}
```
## 渲染列表 {#render-the-list}
把相同的 children 传给 Iterator,它会为每条记录重新提供一次上下文。
```tsx
<ul>
<RecordsIterator data={products}>
<li>
<ProductName />
<ProductPrice />
</li>
</RecordsIterator>
</ul>
```
当 `data` 为空、未定义,或没有提供 children/iterator 时,Iterator 返回 `null`。加载、错误和空状态由外层请求界面处理。
## 使用迭代回调 {#iterator-callback}
简单场景可以直接读取回调参数。回调仍然位于对应记录的上下文中,因此内部组件可以继续使用 Hooks。
```tsx
<RecordsIterator
data={products}
iterator={(product, index) => (
<article>
<span>#{index + 1}</span>
<ProductName />
<button onClick={() => addToCart(product.id)}>Add</button>
</article>
)}
/>
```
## 添加分隔内容 {#add-separators}
使用 `separator` 在相邻记录之间插入分隔内容。它不会在第一条记录之前或最后一条记录之后渲染。回调参数是分隔符后面那条记录的索引,并且分隔内容位于对应记录的 `RecordProvider` 之外。
```tsx
<RecordsIterator
data={products}
separator={(index) => <hr aria-label={`第 ${index} 个分隔符`} />}
>
<ProductCard />
</RecordsIterator>
```
@@ -0,0 +1,73 @@
---
title: 提供并读取记录
description: 使用 RecordProvider、useRecord 和 useFieldValue 构建记录感知组件。
order: 10
toc:
- id: provide-a-record
title: 提供记录
- id: read-a-record
title: 读取记录
- id: read-a-field
title: 读取字段
---
## 提供记录 {#provide-a-record}
在获得数据的边界挂载 Provider。`RecordProvider` 接受已经存在的非空记录;请求结果可能为空时,使用 `OptionalRecordProvider`。
```tsx
import { RecordProvider } from "@workspace/record"
function ProductScreen({ product }: { product: Product }) {
return (
<RecordProvider value={product}>
<ProductDetails />
</RecordProvider>
)
}
```
```tsx
import { OptionalRecordProvider } from "@workspace/record"
;<OptionalRecordProvider value={query.data}>
<ProductDetails />
</OptionalRecordProvider>
```
## 读取记录 {#read-a-record}
`useRecord` 在没有 Provider 或数据尚未加载时返回 `undefined`。
```tsx
function ProductDetails() {
const product = useRecord<Product>()
if (!product) return <p>Loading…</p>
return <h2>{product.name}</h2>
}
```
记录感知组件也可以接受可选的 `record` prop。显式记录优先于上下文,方便单独预览和测试组件。
```tsx
function ProductTitle({ record }: { record?: Product }) {
const product = useRecord({ record })
return product ? <h2>{product.name}</h2> : null
}
```
## 读取字段 {#read-a-field}
`useFieldValue` 支持直接字段、嵌套对象和数组数字段。路径使用点分隔。
```tsx
const city = useFieldValue<Customer, "address.city">({
source: "address.city",
defaultValue: "Unknown",
})
const firstSku = useFieldValue<Order, "items.0.sku">({
source: "items.0.sku",
})
```
+28
View File
@@ -0,0 +1,28 @@
---
title: 概览
description: 了解 Record 包如何在数据驱动界面中传递当前记录。
order: 1
toc:
- id: package-role
title: 包的职责
- id: capabilities
title: 主要能力
- id: design-boundary
title: 设计边界
---
## 包的职责 {#package-role}
`@workspace/record` 是一个无 UI 的 React 记录上下文层。这里的“记录”不是特定对象类型:除 `undefined` 和 `null` 外,数字、布尔值、字符串、数组、函数和普通对象都可以作为记录。它让后代组件读取当前值,而不需要逐层传递 `record` prop。
## 主要能力 {#capabilities}
- 使用 `RecordProvider` 提供当前记录。
- 使用 `useRecord` 读取上下文,或通过显式记录覆盖上下文。
- 使用 `useFieldValue` 按类型安全的点路径读取嵌套字段。
- 使用 `RecordsIterator` 为列表中的每条数据创建隔离的记录上下文。
- 使用 `OptionalRecordProvider` 让组件同时支持独立使用和上下文组合。
## 设计边界 {#design-boundary}
该包不负责请求、缓存、分页、表单状态或 UI。请求层只需把已加载的值交给 Provider 或 Iterator。`undefined` 和 `null` 表示没有可提供的记录;`0`、`false` 和空字符串仍是有效记录。表单中的实时输入值仍应由表单状态读取。