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

文章目录

前言

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 中的实际收益

Rendering Patterns

这是系列的第四部分。

Animate SVG wrappers, not SVG elements directly

「不要直接在 SVG 元素上做动画」

核心问题

  • SVG 元素本身(<path><circle>)渲染成本高
  • 动画会 频繁触发 repaint / reflow
  • 会严重影响性能,尤其在大量节点或复杂图形中

反例:直接动画

ts 复制代码
<svg width="100" height="100">
  <circle
    cx="50"
    cy="50"
    r="40"
    fill="red"
    style={{ transform: `rotate(${angle}deg)` }}
  />
</svg>

每次 angle 更新,浏览器必须重绘整个 <circle>

推荐:动画容器

ts 复制代码
<div style={{ transform: `rotate(${angle}deg)` }}>
  <svg width="100" height="100">
    <circle cx="50" cy="50" r="40" fill="red" />
  </svg>
</div>

好处:

  • 浏览器只在 <div> 上做 GPU transform
  • <svg> 内容不会被重复绘制
  • 动画性能大幅提升

典型场景

  • 仪表盘指针
  • loading spinner
  • 图表动态旋转

Use content-visibility: auto for long lists

「长列表使用 content-visibility 延迟渲染」

核心问题

  • 浏览器渲染大 DOM(数百 / 千行)性能低
  • 每次 scroll / paint 都计算 layout

反例:普通列表

ts 复制代码
<ul>
  {data.map(item => <li key={item.id}>{item.name}</li>)}
</ul>
  • 1000 行 → 每次渲染 / scroll 都会 layout / paint

推荐:content-visibility

ts 复制代码
<ul style={{ contentVisibility: 'auto', containIntrinsicSize: '1000px' }}>
  {data.map(item => <li key={item.id}>{item.name}</li>)}
</ul>

好处:

  • 浏览器只渲染可视区域
  • DOM 节点仍在 document flow
  • 性能接近虚拟列表,但不依赖 JS

额外技巧

  • contain-intrinsic-size 提前占位
  • 表格、卡片、长文列表 非常适用

Prevent hydration mismatch with inline scripts

「避免 hydration mismatch / 客户端渲染与服务端不一致」

核心问题

  • React SSR + RSC / Next.js
  • 服务端生成 HTML → 客户端 hydrate
  • 如果 inline JS 改变 DOM 或插入元素
  • 会导致 Hydration Mismatch → 控制台报错 / UI 闪烁

反例:SSR 内直接修改 DOM

ts 复制代码
<div dangerouslySetInnerHTML={{ __html: `<script>document.body.style.background='red'</script>` }} />
  • 服务端生成的 DOM 和客户端 React DOM 不一致
  • React hydrate 失败

推荐做法

  • useEffect / useLayoutEffect 在客户端处理
tsx 复制代码
useEffect(() => {
  document.body.style.background = 'red'
}, [])

SSR 阶段不改 DOM → 避免 mismatch

场景

  • 动态插入广告 / 脚本
  • 第三方库初始化
  • UI 初始化特效

Use explicit conditional rendering

「条件渲染用三元表达式,而不是 &&」

核心问题

  • false && <Component /> 会渲染 false → 有时造成空 DOM / Hydration mismatch
  • 特别在 SSR / Client Hydration 时容易出错

反例:用 &&

tsx 复制代码
{isVisible && <Modal />}
  • SSR: isVisible=false → 渲染 false
  • Client: isVisible=true → 渲染 <Modal />
  • React 可能报 hydration mismatch

推荐:用三元

tsx 复制代码
{isVisible ? <Modal /> : null}
  • SSR / Client 渲染保持一致
  • Hydration 安全

额外注意

  • 对列表也适用:
tsx 复制代码
{/* ❌ 不推荐 */}
{items.length && <List items={items} />}

{/* ✅ 推荐 */}
{items.length > 0 ? <List items={items} /> : null}

总结

Rendering Patterns = 让浏览器和 React 都高效

  • SVG 动画 → wrapper transform
  • 长列表 → content-visibility
  • SSR → hydrate 安全
  • 条件渲染 → 明确三元
相关推荐
hpoenixf18 小时前
2026 年前端面试问什么
前端·面试
还是大剑师兰特18 小时前
Vue3 中的 defineExpose 完全指南
前端·javascript·vue.js
泯泷18 小时前
阶段一:从 0 看懂 JSVMP 架构,先在脑子里搭出一台最小 JSVM
前端·javascript·架构
mengchanmian19 小时前
前端node常用配置
前端
华洛19 小时前
利好打工人,openclaw不是企业提效工具,而是个人助理
前端·javascript·产品经理
xkxnq19 小时前
第六阶段:Vue生态高级整合与优化(第93天)Element Plus进阶:自定义主题(变量覆盖)+ 全局配置与组件按需加载优化
前端·javascript·vue.js
A黄俊辉A20 小时前
vue css中 :global的使用
前端·javascript·vue.js
小码哥_常21 小时前
被EdgeToEdge适配折磨疯了,谁懂!
前端
小码哥_常21 小时前
从Groovy到KTS:Android Gradle脚本的华丽转身
前端
灵感__idea21 小时前
Hello 算法:复杂问题的应对策略
前端·javascript·算法