VERSION: 2.88.0
name: vercel-react-best-practices description: React 和 Next.js 性能优化指南,由 Vercel 工程团队提供。在编写、审查或重构 React/Next.js 代码时使用。适用于涉及 React 组件、Next.js 页面、数据获取、包优化或性能改进的任务。触发任务时可以使用 Bash、Read、Write、Edit、Grep、Glob、Task 等工具。
Vercel React 最佳实践
v2.88 关键变更(模型无关)
- 模型无关:使用在
~/.claude/settings.json或 CLI/env vars 中配置的模型 - 无需标志:与配置的默认模型一起工作
- 灵活:适用于 GLM-5、Claude、Minimax 或任何配置的模型
- 设置驱动:通过
ANTHROPIC_DEFAULT_*_MODELenv vars 选择模型
Vercel 工程团队提供的 React 和 Next.js 应用的综合性能优化指南。包含 8 个类别的 45 条规则,按影响优先级排序。
何时应用
参考这些指南时:
- 编写新的 React 组件或 Next.js 页面
- 实施数据获取(客户端或服务器端)
- 审查代码以查找性能问题
- 重构现有的 React/Next.js 代码
- 优化包大小或加载时间
按优先级排序的规则类别
| 优先级 | 类别 | 影响 | 前缀 |
|---|---|---|---|
| 1 | 消除瀑布流 | 严重 | async- |
| 2 | 包大小优化 | 严重 | bundle- |
| 3 | 服务器端性能 | 高 | server- |
| 4 | 客户端数据获取 | 中高 | client- |
| 5 | 重新渲染优化 | 中 | rerender- |
| 6 | 渲染性能 | 中 | rendering- |
| 7 | JavaScript 性能 | 低-中 | js- |
| 8 | 高级模式 | 低 | advanced- |
快速参考
1. 消除瀑布流(严重)
async-defer-await- 将 await 移动到实际使用的分支中async-parallel- 对独立操作使用 Promise.all()async-dependencies- 对部分依赖使用 better-allasync-api-routes- 在 API 路由中尽早开始承诺,晚些时候等待async-suspense-boundaries- 使用 Suspense 流式传输内容
2. 包大小优化(严重)
bundle-barrel-imports- 直接导入,避免桶文件bundle-dynamic-imports- 对重型组件使用 next/dynamicbundle-defer-third-party- 在水合后加载分析/日志记录bundle-conditional- 仅在功能激活时加载模块bundle-preload- 在悬停/聚焦时预加载,以感知速度
3. 服务器端性能(高)
server-cache-react- 使用 React.cache() 进行每个请求的去重server-cache-lru- 使用 LRU 缓存进行跨请求缓存server-serialization- 最小化传递给客户端组件的数据server-parallel-fetching- 重构组件以并行获取server-after-nonblocking- 对非阻塞操作使用 after()
4. 客户端数据获取(中高)
client-swr-dedup- 使用 SWR 进行自动请求去重client-event-listeners- 去除全局事件侦听器的重复
5. 重新渲染优化(中)
rerender-defer-reads- 不要订阅仅在回调中使用的状态rerender-memo- 将昂贵的工作提取到记忆组件中rerender-dependencies- 在效果中使用原始依赖rerender-derived-state- 订阅派生的布尔值,而不是原始值rerender-functional-setstate- 使用功能性 setState 进行稳定的回调rerender-lazy-state-init- 为昂贵的值向 useState 传递函数rerender-transitions- 使用 startTransition 进行非紧急更新
6. 渲染性能(中)
rendering-animate-svg-wrapper- 动画 div 包装器,而不是 SVG 元素rendering-content-visibility- 对长列表使用 content-visibilityrendering-hoist-jsx- 在组件外部提取静态 JSXrendering-svg-precision- 降低 SVG 坐标精度rendering-hydration-no-flicker- 使用内联脚本进行客户端独有的数据rendering-activity- 使用 Activity 组件进行显示/隐藏rendering-conditional-render- 使用三元运算符,而不是 && 进行条件渲染
7. JavaScript 性能(低-中)
js-batch-dom-css- 通过类或 cssText 组 CSS 更改js-index-maps- 为重复查找构建 Mapjs-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- 在循环外提升 RegExp 创建js-min-max-loop- 使用循环进行 min/max,而不是排序js-set-map-lookups- 使用 Set/Map 进行 O(1) 查找js-tosorted-immutable- 使用 toSorted() 进行不可变性
8. 高级模式(低)
advanced-event-handler-refs- 在 refs 中存储事件处理程序advanced-use-latest- useLatest 用于稳定的回调 refs
关键性能规则
1.1 延迟直到需要时
将 await 操作移动到实际使用的分支中,以避免阻塞不需要它们的代码路径。
错误:两个分支都被阻塞
async function handleRequest(userId: string, skipProcessing: boolean) {
const userData = await fetchUserData(userId)
if (skipProcessing) {
// 立即返回,但仍然等待 userData
return { skipped: true }
}
return processUserData(userData)
}
正确:仅在需要时阻塞
async function handleRequest(userId: string, skipProcessing: boolean) {
if (skipProcessing) {
// 立即返回,无需等待
return { skipped: true }
}
const userData = await fetchUserData(userId)
return processUserData(userData)
}
1.2 基于依赖的并行化
对于部分依赖的操作,使用 better-all 以最大化并行性。
错误:配置文件不必要地等待配置文件
const [user, config] = await Promise.all([
fetchUser(),
fetchConfig()
])
const profile = await fetchProfile(user.id)
正确:配置文件和配置文件并行运行
import { all } from 'better-all'
const { user, config, profile } = await all({
async user() { return fetchUser() },
async config() { return fetchConfig() },
async profile() {
return fetchProfile((await this.$.user).id)
}
})
2.1 避免桶文件导入
直接从模块导入,而不是桶文件,以实现更好的树摇。
错误:桶文件导入
import { Button, Input, Card, Modal } from '@/components'
正确:直接导入
import Button from '@/components/Button'
import Input from '@/components/Input'
import Card from '@/components/Card'
import Modal from '@/components/Modal'
2.4 重型组件的动态导入
对初始渲染不需要的重型组件使用 next/dynamic。
import dynamic from 'next/dynamic'
const HeavyChart = dynamic(() => import('@/components/HeavyChart'), {
loading: () => <p>Loading...</p>,
ssr: false // 如果不需要 SSR,则禁用
})
3.6 使用 React.cache() 进行每个请求的去重
使用 React.cache() 在同一请求中去重调用。
import { cache } from 'react'
const getUser = cache(async (id: string) => {
return db.user.findUnique({ where: { id } })
})
// 两个调用在同一个请求中返回相同的承诺
const user1 = await getUser('123')
const user2 = await getUser('123') // 没有额外的数据库查询
4.3 使用 SWR 进行自动去重
使用 SWR 进行自动请求去重和缓存。
import useSWR from 'swr'
function useUser(id: string) {
return useSWR(`/api/user/${id}`, fetcher)
}
5.2 提取到记忆组件
将昂贵的工作提取到记忆组件中,以防止不必要的重新渲染。
// 之前:每次渲染都会进行昂贵的计算
function Dashboard({ data }) {
const summary = computeSummary(data) // 每次渲染都会运行
return <div>{summary}</div>
}
// 之后:记忆组件
const Summary = memo(({ data }) => {
return <div>{computeSummary(data)}</div>
})
function Dashboard({ data }) {
return <Summary data={data} />
}
5.7 使用转换进行非紧急更新
使用 startTransition 进行非紧急更新,以保持 UI 的响应性。
import { useState, startTransition } from 'react'
function SearchResults({ query }) {
const [results, setResults] = useState([])
function handleChange(e) {
startTransition(() => {
setResults(search(e.target.value))
})
}
return <input onChange={handleChange} />
}
版本: 1.0.0 作者: Vercel 工程团队 许可证: MIT 参考: https://github.com/vercel-labs/agent-skills/tree/main/skills/react-best-practices