how-to-use-react
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseReact の使い方
React 的使用方法
大本は次の資料で、masseater/typescript-template から作ったリポジトリ向けに読み替えてある。読み替えと原典が食い違うときは読み替えを採る。
- 非同期と性能: https://github.com/vercel-labs/agent-skills/tree/main/skills/react-best-practices
- React 19 の書き方: https://github.com/adhhamdev/modern-react-guidance
- 宣言的 UI とトランジション: https://speakerdeck.com/uhyo/react-no-sekkeiron
- 操作を止めないミューテーション: https://zenn.dev/uhyo/articles/async-react-action-queue
- 重い派生の一貫性: https://zenn.dev/uhyo/articles/async-react-debounce
- コンポーネント API: https://imply.io/blog/an-opinionated-guide-to-component-apis
- 名前とファイル: https://gist.github.com/rafaelrozon/9fd6bc9efbce3e70311b364f87b89241
主要依据以下资料,并已针对基于 masseater/typescript-template 创建的仓库进行调整。如果调整内容与原始资料不一致,则以调整后的内容为准。
- 异步与性能:https://github.com/vercel-labs/agent-skills/tree/main/skills/react-best-practices
- React 19 的编写方式:https://github.com/adhhamdev/modern-react-guidance
- 声明式 UI 与 Transition:https://speakerdeck.com/uhyo/react-no-sekkeiron
- 不中断操作的 Mutation:https://zenn.dev/uhyo/articles/async-react-action-queue
- 高开销派生值的一致性:https://zenn.dev/uhyo/articles/async-react-debounce
- 组件 API:https://imply.io/blog/an-opinionated-guide-to-component-apis
- 命名与文件:https://gist.github.com/rafaelrozon/9fd6bc9efbce3e70311b364f87b89241
置き分け
职责划分
| やりたいこと | 使うもの | 使わないもの |
|---|---|---|
| 画面の一時状態、フォームの値、ツリーをまたいで共有する値 | Effect Atom( | |
| サーバーデータ | TanStack Query( | |
| ミューテーションの pending と error | TanStack Query の | 自前の pending フラグ、 |
| 順番が仕様のミューテーション | 同じ | 自前のキュー、ボタンを無効にして操作列を止める |
| 楽観更新 | | 自前の巻き戻し状態 |
| 急がない更新・重い派生 | | タイマーデバウンス |
| ref | 関数の props | |
| 隠しても状態を残す | | 条件付きアンマウントで状態を捨てる |
| 遷移のアニメーション | | |
| Effect で最新の props を使う | | その関数を依存配列に足して購読をやり直す |
| 要实现的事情 | 使用 | 不使用 |
|---|---|---|
| 界面的临时状态、表单值、跨组件树共享的值 | Effect Atom( | |
| 服务端数据 | TanStack Query( | 使用 |
| Mutation 的 pending 和 error | TanStack Query 的 | 自行维护的 pending 标志、 |
| 顺序有明确要求的 Mutation | 使用相同 | 自定义队列、禁用按钮并中断操作序列 |
| 乐观更新 | | 自行维护的回滚状态 |
| 不紧急的更新、高开销派生值 | | 基于计时器的 debounce |
| ref | 函数形式的 props | |
| 隐藏后仍保留状态 | | 通过条件卸载丢弃状态 |
| 过渡动画 | | |
| 在 Effect 中使用最新的 props | | 将该函数加入依赖数组并重新建立订阅 |
メモ化
记忆化
React Compiler が有効なリポジトリでは 、、 を書かない。
Compiler が無いリポジトリでは、 のルールが props に渡す関数やオブジェクトの作り直しを指摘した箇所にだけ / を書く。それ以外は計測で遅いと分かってから足す。
useMemouseCallbackmemoreact-perfuseCallbackuseMemo在启用了 React Compiler 的仓库中,不编写 、、。
useMemouseCallbackmemo在没有 Compiler 的仓库中,仅当 规则指出传入 props 的函数或对象被重复创建时,才在这些位置编写 / 。除此之外,只有在测量确认性能缓慢后再添加。
react-perfuseCallbackuseMemoコンポーネントを書くとき
编写组件时
- 派生値はレンダー中に計算する。Effect で props を state にコピーしない。
- Effect は React の外(DOM、計測、購読、ウィジェット)と同期するときだけ書き、後始末を返す()。
references/effects-and-data.md - イベントで起きる画面の変化はトランジションが既定である()。
references/design-theory.md - 操作列を止めないミューテーションは と組み合わせ、追加の操作を pending で無効にしない(
useOptimistic)。references/action-queue.md - 重い一覧は入力と を分け、タイマーデバウンスを書かない(
useDeferredValue)。references/deferred-consistency.md - 、
<Activity>、<ViewTransition>の使いどころはuseEffectEvent。references/concurrent-ux.md - props の形は 、名前とファイルは
references/component-apis.md。references/naming.md
- 派生值在渲染期间计算。不要在 Effect 中将 props 复制到 state 中。
- 仅当 Effect 需要与 React 外部的系统(DOM、测量、订阅、widget)同步时才编写,并返回清理函数()。
references/effects-and-data.md - 由事件引起的界面变化默认使用 Transition()。
references/design-theory.md - 不中断操作序列的 Mutation 应与 结合使用,不要因 pending 而禁用后续操作(
useOptimistic)。references/action-queue.md - 对于开销较大的列表,将输入与 分离,不要编写基于计时器的 debounce(
useDeferredValue)。references/deferred-consistency.md - 、
<Activity>、<ViewTransition>的使用场景参见useEffectEvent。references/concurrent-ux.md - props 的形态参见 ,命名与文件参见
references/component-apis.md。references/naming.md
非同期の瀑布
异步瀑布
独立した処理を、前の結果を使わないのに順番に待たない。React の他の性能の話より先に、この節を当てる。詳細は 。
references/async.md- Effect なら か
Effect.allにEffect.forEachを渡す。順番が仕様なら{ concurrency: "unbounded" }と書く。省略しない。{ concurrency: 1 } - Effect の外の Promise なら 。
Promise.all - 依存が一部だけのときは、依存しない側を先に始め、依存する側は で必要な値ができてから始める。両方を一つの
Effect.flatMapに載せる。Effect.all
ts
const loaded = Effect.all(
{
config: fetchConfig,
profile: fetchUser.pipe(Effect.flatMap((user) => fetchProfile(user.id))),
},
{ concurrency: "unbounded" },
);不要让彼此独立的任务在前一个任务的结果尚未返回时依次等待。在讨论其他 React 性能问题之前,应先检查这一部分。详情参见 。
references/async.md- 如果使用 Effect,则向 或
Effect.all传入Effect.forEach。如果顺序有明确要求,则写入{ concurrency: "unbounded" }。不能省略。{ concurrency: 1 } - 如果是 Effect 之外的 Promise,则使用 。
Promise.all - 当只有部分任务存在依赖时,先启动不依赖其他任务的部分;依赖任务则通过 等待所需值就绪后再启动。两者都放入同一个
Effect.flatMap中。Effect.all
ts
const loaded = Effect.all(
{
config: fetchConfig,
profile: fetchUser.pipe(Effect.flatMap((user) => fetchProfile(user.id))),
},
{ concurrency: "unbounded" },
);採らない原典の箇所
不采用的原始资料内容
| 原典 | 代わり |
|---|---|
Next.js( | TanStack Start のローダー |
| SWR | TanStack Query |
| |
| |
| ハンドラを ref にしまう | |
| Redux の Action / Reducer / Selector | Effect Atom と TanStack Query、FSD の |
不確かな API の形は react.dev の該当リファレンスを見る。原典の例を、上の表が使わないとしたフックのまま写さない。
| 原始资料 | 替代方案 |
|---|---|
Next.js( | TanStack Start 的 loader |
| SWR | TanStack Query |
使用 | |
| |
| 将 handler 存入 ref | |
| Redux 的 Action / Reducer / Selector | Effect Atom 与 TanStack Query,以及 FSD 的 |
对于不确定的 API 形态,请查阅 react.dev 上对应的参考文档。不要直接照抄原始资料中仍使用上表明确弃用 hook 的示例。