news 2026/6/23 23:40:20

Vercel 团队 10 年 React 性能优化经验:10 大核心策略让性能提升 300%

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Vercel 团队 10 年 React 性能优化经验:10 大核心策略让性能提升 300%

Vercel 最近发布了 React 最佳实践库,将十余年来积累的 React 和 Next.js优化经验整合到了一个指南中。

其中一共包含8 个类别、40 多条规则

这些原则并不是纸上谈兵,而是 Vercel 团队在 10 余年从无数生产代码库中总结出的经验之谈。它们已经被无数成功案例验证,能切实改善用户体验和业务指标。

以下将是对你的 React 和 Next.js 项目影响最大的 10 大实践。

1. 将独立的异步操作并行

请求瀑布流是 React 应用性能的头号杀手。

每次顺序执行 await 都会增加网络延迟,消除它们可以带来最大的性能提升。

❌ 错误:

asyncfunctionPage(){constuser=awaitfetchUser();constposts=awaitfetchPosts();return<Dashboard user={user}posts={posts}/>;}

✅ 正确:

asyncfunctionPage(){const[user,posts]=awaitPromise.all([fetchUser(),fetchPosts()]);return<Dashboard user={user}posts={posts}/>;}

当处理多个数据源时,这个简单的改变可以将页面加载时间减少数百毫秒。

2. 避免桶文件导入

从桶文件导入会强制打包程序解析整个库,即使你只需要其中一个组件。

这就像把整个衣柜都搬走,只为了穿一件衣服。

❌ 错误:

import{Check,X,Menu}from"lucide-react";

✅ 正确:

importCheckfrom"lucide-react/dist/esm/icons/check";importXfrom"lucide-react/dist/esm/icons/x";importMenufrom"lucide-react/dist/esm/icons/menu";

更好的方式(使用 Next.js 配置):

// next.config.jsmodule.exports={experimental:{optimizePackageImports:["lucide-react","@mui/material"],},};// 然后保持简洁的导入方式import{Check,X,Menu}from"lucide-react";

直接导入可将启动速度提高 15-70%,构建难度降低 28%,冷启动速度提高 40%,HMR 速度显著提高。

3. 使用延迟状态初始化

当初始化状态需要进行耗时的计算时,将初始化程序包装在一个函数中,确保它只运行一次。

❌ 错误:

functionComponent(){const[config,setConfig]=useState(JSON.parse(localStorage.getItem("config")));return<div>{config.theme}</div>;}

✅ 正确:

functionComponent(){const[config,setConfig]=useState(()=>JSON.parse(localStorage.getItem("config")));return<div>{config.theme}</div>;}

组件每次渲染都会从 localStorage 解析 JSON 配置,但其实它只需要在初始化的时候读取一次,将其封装在回调函数中可以消除这种浪费。

4. 最小化 RSC 边界的数据传递

React服务端/客户端边界会将所有对象属性序列化为字符串并嵌入到 HTML 响应中,这会直接影响页面大小和加载时间。

❌ 错误:

asyncfunctionPage(){constuser=awaitfetchUser();// 50 fieldsreturn<Profile user={user}/>;}("use client");functionProfile({user}){return<div>{user.name}</div>;// uses 1 field}

✅ 正确:

asyncfunctionPage(){constuser=awaitfetchUser();return<Profile name={user.name}/>;}("use client");functionProfile({name}){return<div>{name}</div>;}

只传递客户端组件实际需要的数据。

5. 动态导入大型组件

仅在功能激活时加载大型库,减少初始包体积。

❌ 错误:

import{AnimationPlayer}from"./heavy-animation-lib";functionComponent(){const[enabled,setEnabled]=useState(false);returnenabled?<AnimationPlayer/>:null;}

✅ 正确:

functionAnimationPlayer({enabled,setEnabled}){const[frames,setFrames]=useState(null);useEffect(()=>{if(enabled&&!frames&&typeofwindow!=="undefined"){import("./animation-frames.js").then((mod)=>setFrames(mod.frames)).catch(()=>setEnabled(false));}},[enabled,frames,setEnabled]);if(!frames)return<Skeleton/>;return<Canvas frames={frames}/>;}

typeof window可以防止将此模块打包用于SSR,优化服务端包体积和构建速度。

6. 延迟加载第三方脚本

分析和跟踪脚本不要阻塞用户交互。

❌ 错误:

exportdefaultfunctionRootLayout({children}){useEffect(()=>{initAnalytics();},[]);return(<html><body>{children}</body></html>);}

✅ 正确:

import{Analytics}from"@vercel/analytics/react";exportdefaultfunctionRootLayout({children}){return(<html><body>{children}<Analytics/></body></html>);}

在水合后加载分析脚本,优先处理交互内容。

7. 使用 React.cache() 进行请求去重

防止服务端在同一渲染周期内重复请求。

❌ 错误:

asyncfunctionSidebar(){constuser=awaitfetchUser();return<div>{user.name}</div>;}asyncfunctionHeader(){constuser=awaitfetchUser();// 重复请求return<nav>{user.email}</nav>;}

✅ 正确:

import{cache}from"react";constgetUser=cache(async()=>{returnawaitfetchUser();});asyncfunctionSidebar(){constuser=awaitgetUser();return<div>{user.name}</div>;}asyncfunctionHeader(){constuser=awaitgetUser();// 已缓存,无重复请求return<nav>{user.email}</nav>;}

8. 实现跨请求数据的 LRU 缓存

React.cache() 仅在单个请求内有效,因此对于跨连续请求共享的数据,使用 LRU 缓存。

❌ 错误:

import{LRUCache}from"lru-cache";constcache=newLRUCache({max:1000,ttl:5*60*1000,// 5 分钟});exportasyncfunctiongetUser(id){constcached=cache.get(id);if(cached)returncached;constuser=awaitdb.user.findUnique({where:{id}});cache.set(id,user);returnuser;}

这在 Vercel 的 Fluid Compute 中特别有效,多个并发请求共享同一个函数实例。

9. 通过组件组合实现并行化

React 服务端组件在树状结构中按顺序执行,因此需要使用组合对组件树进行重构以实现并行化数据获取:

❌ 错误:

asyncfunctionPage(){constdata=awaitfetchPageData();return(<><Header/><Sidebar data={data}/></>);}

✅ 正确:

asyncfunctionPage(){return(<><Header/><Sidebar/></>);}asyncfunctionSidebar(){constdata=awaitfetchPageData();return<div>{data.content}</div>;}

这样一来,页眉和侧边栏就可以并行获取数据了。

10. 使用 SWR 进行客户端请求去重

当客户端上的多个组件请求相同的数据时,SWR 会自动对请求进行去重。

❌ 错误:

functionUserProfile(){const[user,setUser]=useState(null);useEffect(()=>{fetch("/api/user").then((r)=>r.json()).then(setUser);},[]);return<div>{user?.name}</div>;}functionUserAvatar(){const[user,setUser]=useState(null);useEffect(()=>{fetch("/api/user").then((r)=>r.json()).then(setUser);},[]);return<img src={user?.avatar}/>;}

✅ 正确:

importuseSWRfrom"swr";constfetcher=(url)=>fetch(url).then((r)=>r.json());functionUserProfile(){const{data:user}=useSWR("/api/user",fetcher);return<div>{user?.name}</div>;}functionUserAvatar(){const{data:user}=useSWR("/api/user",fetcher);return<img src={user?.avatar}/>;}

SWR 只发出一个请求,并将结果在两个组件之间共享。

11. 总结

这些最佳实践的美妙之处在于:它们不是复杂的架构变更。大多数都是简单的代码修改,却能产生显著的性能改进。

一个 600ms 的瀑布等待时间,会影响每一位用户,直到被修复。

一个桶文件导入造成的包膨胀,会减慢每一次构建和每一次页面加载

所以越早采用这些实践,就能避免积累越来越多的性能债务。

现在开始应用这些技巧,让你的 React 应用快如闪电吧!

我是冴羽,10 年笔耕不辍,专注前端领域,更新了 10+ 系列、300+ 篇原创技术文章,翻译过 Svelte、Solid.js、TypeScript 文档,著有小册《Next.js 开发指南》、《Svelte 开发指南》、《Astro 实战指南》。

欢迎围观我的“网页版朋友圈”,关注我的公众号:冴羽(或搜索 yayujs),每天分享前端知识、AI 干货。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/19 20:54:12

Java集合接口深度剖析:List、Map、Set的特点及应用

文章目录 Java集合接口深度剖析&#xff1a;List、Map、Set的特点及应用一、引言&#xff1a;为什么要学习集合框架&#xff1f;二、List接口&#xff1a;有序的“购物车”1. List的特点2. 常用实现类&#xff08;1&#xff09;ArrayList&#xff08;2&#xff09;LinkedList&a…

作者头像 李华
网站建设 2026/6/22 11:48:20

React 项目的启动方式

一、启动前先确认 3 件事&#xff08;很重要&#xff09; 在项目根目录&#xff08;有 package.json 的地方&#xff09;&#xff1a; 1. 确认 Node 版本 node -v npm -v一般建议 Node ≥ 18&#xff08;Vite / 现代 React 很稳&#xff09; 如果报错&#xff0c;大概率是…

作者头像 李华
网站建设 2026/6/23 2:20:23

小目标识别表现:远处路牌、微小文字能否清晰读取?

小目标识别表现&#xff1a;远处路牌、微小文字能否清晰读取&#xff1f; 一张照片里&#xff0c;有近处的行人、中景的车辆、远处的楼宇——但你有没有注意过&#xff0c;街角那块被树影遮挡的交通指示牌&#xff1f;或者广告牌角落里几毫米高的联系方式&#xff1f;又或者监控…

作者头像 李华
网站建设 2026/6/17 18:35:40

音频太长怎么办?分段处理5分钟以上录音的小技巧

音频太长怎么办&#xff1f;分段处理5分钟以上录音的小技巧 你有没有遇到过这样的情况&#xff1a;一段40分钟的会议录音&#xff0c;想转成文字整理纪要&#xff0c;结果上传到语音识别工具时被提示“文件超时”或“处理失败”&#xff1f;又或者等了十几分钟&#xff0c;界面…

作者头像 李华
网站建设 2026/6/22 15:16:13

Clawdbot+Qwen3-32B:企业内部智能客服系统快速搭建方案

ClawdbotQwen3-32B&#xff1a;企业内部智能客服系统快速搭建方案 1. 为什么企业需要自己的智能客服系统 你有没有遇到过这些情况&#xff1a; 客户咨询高峰期&#xff0c;客服团队手忙脚乱&#xff0c;响应延迟超过5分钟&#xff1b; 新员工入职要花两周时间背产品手册和FAQ…

作者头像 李华