news 2026/2/10 22:23:55

WHAT - Vercel react-best-practices 系列(三)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
WHAT - Vercel react-best-practices 系列(三)

文章目录

  • 前言
  • Guidelines
  • Medium-Impact
    • 1. Use SWR for automatic request deduplication
      • 核心问题
      • 反例:手写 useEffect
      • 推荐:SWR 自动去重
      • 一句话总结
    • 2. Defer state reads to usage point
      • 核心问题
      • 反例:提前解构
      • 推荐:用到再读
      • Zustand / Redux / Jotai 都适用
      • 一句话总结
    • 3. Use lazy state initialization for expensive values
      • 核心问题
      • 反例
      • 推荐:lazy init
      • 典型场景
      • 一句话总结
    • 4. Use derived state subscriptions
      • 核心问题
      • 反例
      • 推荐:派生 state
      • 在全局状态库中更重要
      • 一句话总结
    • 5. Apply startTransition for non-urgent updates
      • 核心问题
      • 典型场景
      • 反例:同步更新
      • 推荐:startTransition
      • 什么时候该用 startTransition
  • 总结

前言

react-best-practices

React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.

Guidelines


在这个系列,我会逐条拆解,每一条都给出:

  • 核心问题是什么
  • 为什么会慢(本质原因)
  • 典型业务场景
  • 反例代码
  • 推荐写法
  • 在 React / Next.js 中的实际收益

Medium-Impact

这是系列的第三部分。

这一部分开始从“Server 极致性能”回到“Client 交互体验”,重点不再是 RTT,而是:

减少不必要的 re-render、避免同步阻塞、让用户感觉“很跟手”

1. Use SWR for automatic request deduplication

同一时间只发一次请求

核心问题

在 Client 侧:

  • 多个组件
  • 同一个接口
  • 同时 mount

浏览器会发多次相同请求

反例:手写 useEffect

functionuseUser(){const[data,setData]=useState(null)useEffect(()=>{fetch('/api/user').then(r=>r.json()).then(setData)},[])returndata}
<Header/><Sidebar/>

/api/user被请求两次

推荐:SWR 自动去重

importuseSWRfrom'swr'constfetcher=(url:string)=>fetch(url).then(r=>r.json())functionuseUser(){returnuseSWR('/api/user',fetcher)}

SWR 做了什么?

  • 同 key 只请求一次
  • 多组件共享结果
  • 自动缓存 & revalidate

一句话总结

SWR = Client 版 React.cache

2. Defer state reads to usage point

不要为了“可能用”而提前读 state

核心问题

React 中:

  • 读取 state = 建立订阅
  • state 更新 → 组件 re-render

提前读 = 不必要的 re-render

反例:提前解构

const{user,theme,locale}=useAppStore()

即使只用theme

  • user 更新
  • locale 更新

组件都会重渲染。

推荐:用到再读

consttheme=useAppStore(state=>state.theme)

Zustand / Redux / Jotai 都适用

useSelector(state=>state.user.name)

一句话总结

订阅越小,重渲染越少

3. Use lazy state initialization for expensive values

初始值贵,就别每次算

核心问题

useState(expensiveCompute())
  • 每次 render 都会执行expensiveCompute
  • 即使只用第一次

反例

const[value]=useState(buildBigMap(data))

推荐:lazy init

const[value]=useState(()=>buildBigMap(data))

函数只在初次 render 执行一次

useState 的两种“初始化模式”:

  1. 普通初始化(每次 render 都会算),也就是useState(buildBigMap(data)),React 在 render 前,先执行 buildBigMap,把执行结果作为参数传给 useState,每次 render 都会执行一次。

  2. Lazy 初始化,也就是useState(() => buildBigMap(data)),传递给 useState 的是一个 Initializer function,内部处理如下

functionuseState(initialState){if(isFirstRender){if(typeofinitialState==='function'){state=initialState()}else{state=initialState}}return[state,setState]}

因此,只有在 first render(mount)时:才会执行initialState(),后续 render:直接读取已经保存的 state,不会再碰这个函数。

典型场景

  • JSON.parse
  • 构建索引 Map
  • 复杂正则
  • 大数组预处理

一句话总结

初始 state = 函数

4. Use derived state subscriptions

不要存“算得出来的 state”

核心问题

const[filtered,setFiltered]=useState([])

filtered明明来自list + keyword

双源真相,必出 bug

反例

useEffect(()=>{setFiltered(list.filter(i=>i.name.includes(keyword)))},[list,keyword])

推荐:派生 state

constfiltered=useMemo(()=>{returnlist.filter(i=>i.name.includes(keyword))},[list,keyword])

在全局状态库中更重要

useStore(state=>state.items.filter(i=>i.active))

一句话总结

能算出来,就别存

5. Apply startTransition for non-urgent updates

区分“着急”和“不着急”的更新

React 18 引入了 更新优先级(lanes)

  • Urgent lane:输入、点击、focus
  • Transition lane:可延后更新

核心问题

React 默认:

  • 所有 state 更新都是“紧急的”
  • 大量更新 → 卡顿

典型场景

  • 搜索过滤
  • 表格排序
  • 列表分页
  • tab 切换后加载数据

反例:同步更新

onChange={(e)=>{setKeyword(e.target.value)setFilteredData(filter(data,e.target.value))}}

输入会卡。因为 React 内部的理解是:“这两个 setState 同等重要,必须立刻算完”,如果 filter(data) 很重:

  1. 输入法卡
  2. 光标延迟
  3. 掉帧

二、startTransition 到底做了什么?

推荐:startTransition

import{startTransition}from'react'onChange={(e)=>{setKeyword(e.target.value)startTransition(()=>{setFilteredData(filter(data,e.target.value))})}}

效果:

  • 输入优先
  • 列表稍后更新
  • UI 更丝滑

startTransition = 告诉 React:「这次更新不着急,别挡住用户操作」。没有 startTransition

用户输入 ↓ React:必须算完 filter(500ms) ↓UI更新

使用 startTransition

用户输入 ↓ React:先更新 input(5ms) ↓ 空闲时再算 filter ↓ 更新列表

注意,它不是 setTimeout,比如setTimeout(() => setList(...), 0),也不是 debounce。

对比setTimeoutstartTransition
是否理解 UI
可被中断
与调度器协作
与 Concurrent Rendering

更具体的对比可以阅读:WHAT - React startTransition vs setTimeout vs debounce

什么时候该用 startTransition

场景是否适合
搜索过滤
表格排序
分页切换
Tab 内容切换
输入框 value
hover 状态
modal 开关

总结

它们解决的是三类问题

1️⃣请求重复→ SWR
2️⃣订阅过多→ defer reads / derived state
3️⃣计算 & 更新阻塞→ lazy init / transition

一句话 Client 性能心法

少订阅

少算

慢更新

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

告别文献 “乱炖”!宏智树 AI 手把手教你写出有灵魂的文献综述

作为深耕论文写作科普的教育博主&#xff0c;后台总能刷到这样的求助&#xff1a;“读了几十篇文献&#xff0c;写出来的综述像‘大杂烩’”“观点堆砌没逻辑&#xff0c;被导师批‘没找到研究缺口’”“参考文献格式错一堆&#xff0c;查重率还居高不下”。文献综述不是简单的…

作者头像 李华
网站建设 2026/2/8 0:08:38

0x3f第32天复习 (12;30-12:50)

子串基础前缀和思考前缀和的定义是什么和为k的子数组1min ac两数之和接雨水三数之和ac字母异位词分组ac最长连续序列ac移动零ac无重复字符的最长子串ac找到字符串中所有字母异位词ac滑动窗口最大值1min ac1min ac最小覆盖子串1min ac1min ac思考买卖股票的最佳时机1min ac1min …

作者头像 李华
网站建设 2026/2/9 8:42:27

大模型算法社招面试全攻略:技术要点+简历优化+代码题解析

本文作者分享了从国企跳槽至大模型算法领域社招的完整经历。详细介绍了职业规划考量、简历准备技巧&#xff0c;以及大模型相关技术面试要点&#xff0c;包括SFT、RAG、Agent等热门技术方向。同时提供了常见代码题考察情况和业务方向分析&#xff0c;为想进入大模型领域的求职者…

作者头像 李华
网站建设 2026/2/9 5:08:54

算法题 增减字符串匹配

942. 增减字符串匹配 问题描述 给定只含 "I"&#xff08;增加&#xff09;和 "D"&#xff08;减少&#xff09;的字符串 s&#xff0c;令 n s.length。 根据 s 构造一个排列 perm&#xff08;长度为 n 1&#xff09;&#xff0c;使得对于所有的 i&#x…

作者头像 李华
网站建设 2026/1/30 4:34:00

基于Django的蔬菜批发管理系统设计与实现

基于Django的蔬菜批发管理系统设计与实现 一、系统开发背景与意义 蔬菜批发行业作为农产品流通的关键环节&#xff0c;长期面临供应链效率低、损耗率高、交易流程繁琐等问题。传统模式下&#xff0c;供应商信息分散导致采购比价困难&#xff0c;库存依赖人工盘点易造成积压或缺…

作者头像 李华
网站建设 2026/2/8 2:53:50

京东价格API:历史价格趋势分析与定价参考技术实现

本文介绍如何通过京东开放平台API获取商品历史价格数据&#xff0c;并基于时间序列分析构建定价参考模型。以下为完整技术方案&#xff1a;一、API接入准备认证流程开发者需注册京东宙斯账号&#xff0c;申请price_histroy接口权限&#xff0c;获取app_key和app_secret。请求头…

作者头像 李华