VercelReact最佳实践 vercel-react-best-practices

Vercel 工程团队提供的 React 和 Next.js 应用的性能优化指南,包含 45 条规则,覆盖 8 个优化类别,旨在提升应用性能。

前端开发 0 次安装 2 次浏览 更新于 3/4/2026

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_*_MODEL env 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-all
  • async-api-routes - 在 API 路由中尽早开始承诺,晚些时候等待
  • async-suspense-boundaries - 使用 Suspense 流式传输内容

2. 包大小优化(严重)

  • bundle-barrel-imports - 直接导入,避免桶文件
  • bundle-dynamic-imports - 对重型组件使用 next/dynamic
  • bundle-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-visibility
  • rendering-hoist-jsx - 在组件外部提取静态 JSX
  • rendering-svg-precision - 降低 SVG 坐标精度
  • rendering-hydration-no-flicker - 使用内联脚本进行客户端独有的数据
  • rendering-activity - 使用 Activity 组件进行显示/隐藏
  • rendering-conditional-render - 使用三元运算符,而不是 && 进行条件渲染

7. JavaScript 性能(低-中)

  • js-batch-dom-css - 通过类或 cssText 组 CSS 更改
  • 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 - 在循环外提升 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