来自 Vercel 工程团队的 React 和 Next.js 性能优化指南,涵盖 8 个类别的 57 条规则,用于编写、审查和重构 React 代码。
反应最佳操作是一项面向实际任务的技能,主要用于综合性能优化指南 Vercel Engineering的 React and Next.js 应用程序;包含57条规则, 共8个类别, 按影响排列;
该技能适合需要稳定复用相关能力的场景,可作为自动化工作流的一部分,也便于后续检查、调整和扩展。从功能定位来看,该技能强调把分散的操作要求整理成清晰、可复用的处理流程,使用户能够围绕既定目标快速准备输入、选择执行方式并获得结构化结果。实际使用前应先确认任务范围、数据来源、运行环境、必要权限和关键参数,再依据技能说明逐步执行;
若输入条件不完整,应先补齐信息或采用保守配置,避免因错误假设导致结果偏离需求。执行过程中需要关注工具调用是否成功、接口或依赖是否可用、输出格式是否符合预期,并对异常提示、缺失字段和边界情况进行处理;涉及批量任务时,还应保存进度,避免中断后重复操作。
由 Vercel 工程团队提供的 React 与 Next.js 应用全面性能优化指南。涵盖 8 个类别共 57 条规则,按影响程度排序。
npx clawhub@latest install react-best-practices
提供可落地执行的规则,用于:
react performance, nextjs optimization, bundle size, waterfalls, suspense, server components, rsc, rerender, usememo, dynamic import, parallel fetching, cache, swr
| 优先级 | 类别 | 影响程度 | 规则前缀 |
|---|---|---|---|
| 1 | 消除请求瀑布 | CRITICAL | async- |
| 2 | 包体积优化 | CRITICAL | bundle- |
| 3 | 服务端性能 | HIGH | server- |
| 4 | 客户端数据获取 | MEDIUM-HIGH | client- |
| 5 | 重渲染优化 | MEDIUM | rerender- |
| 6 | 渲染性能 | MEDIUM | rendering- |
| 7 | JavaScript 性能 | LOW-MEDIUM | js- |
| 8 | 高级模式 | LOW | advanced- |
| 规则 | 说明 |
|---|---|
async-defer-await |
将 await 移至实际使用它的分支中 |
async-parallel |
对相互独立的操作使用 Promise.all() |
async-dependencies |
使用 better-all 处理部分依赖关系 |
async-api-routes |
在 API 路由中尽早启动 Promise,延迟 await |
async-suspense-boundaries |
使用 Suspense 流式传输内容 |
| 规则 | 说明 |
|---|---|
bundle-barrel-imports |
直接导入,避免通过 barrel 文件导入 |
bundle-dynamic-imports |
对重型组件使用 next/dynamic |
bundle-defer-third-party |
在 hydration 完成后再加载分析/日志等第三方脚本 |
bundle-conditional |
仅在功能启用时才加载对应模块 |
bundle-preload |
在 hover/focus 时预加载资源,提升感知速度 |
| 规则 | 说明 |
|---|---|
server-auth-actions |
像处理 API 路由一样对 Server Actions 进行身份验证 |
server-cache-react |
使用 React.cache() 实现按请求去重 |
server-cache-lru |
使用 LRU 缓存实现跨请求缓存 |
server-dedup-props |
避免 RSC props 中重复序列化数据 |
server-serialization |
最小化传递给客户端组件的数据量 |
server-parallel-fetching |
重构组件结构以并行发起 fetch 请求 |
server-after-nonblocking |
使用 after() 执行非阻塞操作 |
| 规则 | 说明 |
|---|---|
client-swr-dedup |
使用 SWR 实现自动请求去重 |
client-event-listeners |
去重全局事件监听器 |
client-passive-event-listeners |
对 scroll 等事件使用 passive 监听器 |
client-localstorage-schema |
为 localStorage 数据添加版本号并精简其内容 |
| 规则 | 说明 |
|---|---|
rerender-defer-reads |
不要订阅仅在回调中使用的状态 |
rerender-memo |
将耗时计算提取到 memoized 组件中 |
rerender-memo-with-default-value |
将默认的非原始类型 props 提升至组件外部 |
rerender-dependencies |
在 useEffect 中使用原始类型作为依赖项 |
rerender-derived-state |
订阅派生出的布尔值,而非原始值 |
rerender-derived-state-no-effect |
在渲染阶段推导状态,而非在 effect 中 |
rerender-functional-setstate |
对需保持稳定性的回调使用函数式 setState |
rerender-lazy-state-init |
对开销较大的初始值,向 useState 传入初始化函数 |
rerender-simple-expression-in-memo |
避免对简单原始值使用 memo |
rerender-move-effect-to-event |
将交互逻辑移至事件处理器中 |
rerender-transitions |
对非紧急更新使用 startTransition |
rerender-use-ref-transient-values |
对频繁变化的临时值使用 ref |
| 规则 | 说明 |
|---|---|
rendering-animate-svg-wrapper |
对 div 包裹器进行动画,而非 SVG 元素本身 |
rendering-content-visibility |
对长列表使用 content-visibility |
rendering-hoist-jsx |
将静态 JSX 提取到组件外部 |
rendering-svg-precision |
降低 SVG 坐标精度 |
rendering-hydration-no-flicker |
使用内联 script 传递仅客户端所需的数据 |
rendering-hydration-suppress-warning |
抑制预期存在的 hydration 不匹配警告 |
rendering-activity |
使用 Activity 组件控制显示/隐藏 |
rendering-conditional-render |
条件渲染优先使用三元运算符,而非 && |
rendering-usetransition-loading |
加载状态优先使用 useTransition |
| 规则 | 说明 |
|---|---|
js-batch-dom-css |
通过 CSS 类或 cssText 批量修改样式 |
js-index-maps |
为高频查找构建 Map |
js-cache-property-access |
在循环中缓存对象属性访问 |
js-cache-function-results |
在模块级 Map 中缓存函数结果 |
js-cache-storage |
缓存 localStorage/sessionStorage 的读取操作 |
js-combine-iterations |
将多个 filter/map 合并为单次遍历 |
js-length-check-first |
在执行高开销操作前先检查数组长度 |
js-early-exit |
尽早从函数中返回 |
js-hoist-regexp |
将正则表达式创建逻辑提升至循环外 |
js-min-max-loop |
使用循环而非 sort 实现 min/max 查找 |
js-set-map-lookups |
使用 Set/Map 实现 O(1) 时间复杂度查找 |
js-tosorted-immutable |
使用 toSorted() 保证不可变性 |
| 规则 | 说明 |
|---|---|
advanced-event-handler-refs |
将事件处理器存储在 ref 中 |
advanced-init-once |
每个应用加载周期仅初始化一次 |
advanced-use-latest |
使用 useLatest 获取稳定的回调 ref |
rules/ 目录下的每条规则文件均包含:
rules/async-parallel.md
rules/bundle-barrel-imports.md
rules/rerender-memo.md
如需查看所有规则展开后的完整指南,请查阅:AGENTS.md
这份超过 2900 行的文档包含全部规则的详细代码示例与深入解释,适用于系统性参考。
// 错误:串行获取
const user = await fetchUser()
const posts = await fetchPosts()
// 正确:并行获取
const [user, posts] = await Promise.all([
fetchUser(),
fetchPosts()
])
// 错误:Monaco 打包进主 chunk
import { MonacoEditor } from './monaco-editor'
// 正确:按需加载
const MonacoEditor = dynamic(
() => import('./monaco-editor').then(m => m.MonacoEditor),
{ ssr: false }
)
// 错误:存在闭包过期风险
const addItem = useCallback((item) => {
setItems([...items, item])
}, [items]) // items 每次变更都会导致重新创建
// 正确:始终基于最新状态
const addItem = useCallback((item) => {
setItems(curr => [...curr, item])
}, []) // 引用稳定
import { X } from 'lib')——请直接导入&& ——请改用三元运算符.sort() 原地修改数组——请改用 .toSorted()useEffect([]) 中——请使用模块级守卫