关于 react
react 是面向 React 代码编写与审查的实践指南,供开发者参考。内容涵盖 Effect 使用、渲染性能、数据获取、表单操作及 React 19 迁移,并提供审查清单。
主要功能
- 01Effect 使用与清理建议
- 02重渲染与状态管理指导
- 03数据获取与请求并行化
- 04React 19 表单与迁移要点
- 05性能建议及代码审查清单
适用场景
- 01检查组件是否不必要地使用 Effect
- 02审查订阅、监听器和请求清理
- 03优化数据获取与组件渲染
- 04规划 React 19 升级与表单改造
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ xgent-ai/ skills --skill react安装后在 Claude Code 中输入/react确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/actions.mdcomponent-patterns.mddata-fetching.mdeffect-patterns.mdjs-performance.mdreact19-migration.mdrendering-performance.mdrerender-optimization.md详细介绍
React 最佳实践
编写或审查 React 代码时,请遵循以下指南。
参考文件
请在同一轮中并行阅读所有相关参考资料。提供反馈时请引用它们:
- Effect 模式:何时不需要 Effect、依赖规则、清理、订阅、
useSyncExternalStore、一次性初始化 - 重新渲染优化:
memo/useMemo/useCallback、派生状态、函数式更新、延迟初始化、useDeferredValue、startTransition、useEffectEvent - 组件模式:Refs、
useImperativeHandle、自定义 Hook 规则、受控与非受控、组合优于逐层传递 props、flushSync - 数据获取:并行请求、Suspense 边界、
use()和稳定的 Promise 来源、请求去重、被动监听器、localStorage版本控制 - 渲染性能:
content-visibility、水合不匹配、资源提示、脚本加载、SVG 动画、Activity、useTransition - JS 性能:布局抖动、
Set/Map查找、索引映射、单次遍历、toSorted、requestIdleCallback - Actions:
<form action>、useActionState、useFormStatus、useOptimistic——变更操作的待处理、错误和乐观状态 - React 19 迁移:从 18 升级——根 API、
findDOMNode、forwardRef、defaultProps、旧版 context、字符串 refs、propTypes、JSX 转换、TypeScript 类型、act/test-utils、StrictMode 测试次数
你可能不需要 Effect
Effect 是 React 的逃生舱口,用于与外部系统同步。如果不涉及外部系统,你可能就不需要 Effect。
Need to respond to something?
├── User interaction (click, submit, drag)?
│ └── EVENT HANDLER
├── Props/state changed and need a derived value?
│ └── CALCULATE DURING RENDER
│ └── Measurably expensive? useMemo
├── Need to reset state when an identity prop changes?
│ └── key PROP on the component
└── Component appeared on screen, and there's an external system?
└── EFFECT, with cleanup
确实需要 Effect: 非 React 组件和浏览器 API、订阅(优先使用 useSyncExternalStore)、因组件显示而触发的分析事件、带清理逻辑的数据获取(优先使用数据库)。
不需要 Effect: 为渲染转换数据、处理用户事件、派生状态、串联状态更新、通知父组件、重置状态。
快速参考
Effects
| 情况 | 不要这样做 | 应该这样做 |
|---|---|---|
| 根据 props/state 派生状态 | useState + useEffect | 在渲染期间计算 |
| 开销较大的计算 | 使用 useEffect 缓存 | 使用 useMemo |
| 在 prop 变化时重置状态 | useEffect + setState | 使用 key prop |
| 响应用户事件 | 使用 useEffect 监听状态 | 使用事件处理函数 |
| 通知父组件发生变化 | 使用 useEffect 调用 onChange | 在事件处理函数中调用 |
| 订阅外部存储 | 手动使用 useEffect 订阅 | 使用 useSyncExternalStore |
| 获取数据 | 使用不带清理逻辑的 useEffect | 使用 ignore 标记或数据库 |
| Effect 每次渲染都会重新运行 | 在依赖项中使用对象/函数 | 将创建操作移到 Effect 内部 |
| 缺少依赖项 | eslint-disable exhaustive-deps | 使用函数式更新或 useEffectEvent |
| 应用仅初始化一次 | 使用 useRef 守卫 | 使用模块级标志 |
重新渲染
- 切勿在另一个组件内部定义组件——这会导致组件在每次渲染时重新挂载
- 当下一个状态取决于前一个状态时,使用函数式
setState - 对于开销较大的默认值,使用
useState(() => expensive());普通写法会在每次渲染时运行 - 不要用
useMemo包装简单的布尔值或基本类型表达式 - 拆分组合使用的
useMemo/useEffect——每个只处理一项关注点 - 经常变化但不参与渲染的值(鼠标位置、标志)应存放在 refs 中
- 如果启用了 React Compiler,请跳过手动使用
memo/useMemo/useCallback
数据获取
- 对互不依赖的请求使用
Promise.all();有依赖的请求则逐项串联 - 将
await放到提前返回之后,并置于开销低的同步检查之后 - 每个端点共享一个请求(SWR / React Query),而不是每个组件实例各发一个请求
- 每个获取数据的 effect 都需要
ignore标志或AbortController - 传给
use()的 Promise 应来自 loader、缓存、库或 Server Component,绝不能在渲染期间创建
表单和变更(React 19)
- 优先使用
<form action={fn}>,而不是onSubmit+preventDefault;优先使用useActionState,而不是 loading/error reducer - 将预期错误作为状态从 action 返回;抛出的错误会交给错误边界
useFormStatus从react-dom导入,且只能读取父级<form>- 使用已确认的状态为
useOptimistic提供初始值,并在 Action 中调用其 setter - 在 Action 内
await之后,将状态更新再包在一个startTransition中
升级到 React 19
- 先运行
npx codemod@latest react/19/migration-recipe;升级 PR 只会更改 API 表面 forwardRef仍然有效——ref是普通 prop;可择机转换- 函数组件上的
defaultProps会被忽略,但类组件仍然支持 - StrictMode 仍会让 effects 运行两次;变化在于
useMemo/useCallback结果的复用,以及 ref 回调会被调用两次
性能
- 优化前先测量——进行性能分析,不要凭猜测
- 批量写入 DOM,然后只读取一次;交错操作会强制触发回流
- 对重复查找使用
Set/Map;遍历一次,而不是链式调用.filter().map() - 对 props 和 state 使用
.toSorted()——.sort()会修改原数组 - 使用
requestIdleCallback延后分析和预取
Review 清单
- 每个
useEffect是否都在与外部系统同步?如果没有,请提出替代方案。 - 依赖数组是否完整,且没有禁用 lint 检查?
- 每个订阅、监听器、计时器和 fetch 是否都有清理逻辑?
- 是否存在冗余状态——可以从其他 props 或 state 推导得出?
- 组件是否都定义在模块作用域?
- 互不依赖的异步调用是否已并行化?
- 是否对 props 或 state 使用了会修改原值的数组方法?
- 传给
use()的每个 Promise 是否都能在多次渲染间保持稳定? - 在 React 19 中:表单是否使用 Actions 并将错误作为状态返回?已移除的 API(
findDOMNode、字符串 ref、旧版 context、test-utils)是否都已清除?
评论
支持 Markdown