首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Vue 3 和 React 的第六个差异:性能优化不能只看谁更快,要看谁更容易写对

Vue 3 和 React 的第六个差异:性能优化不能只看谁更快,要看谁更容易写对

原创
作者头像
peace-free
发布2026-06-24 16:24:45
发布2026-06-24 16:24:45
500
举报

Vue 3 和 React 谁性能更好,这是一个很容易吵起来的问题。可惜,这个问题大多数时候问错了。真实项目里,性能瓶颈很少只由框架名字决定。列表渲染规模、组件拆分、状态位置、请求策略、图片资源、打包体积、缓存策略、第三方库,都可能比框架本身更影响用户感受。

更实际的比较方式是:Vue 3 和 React 分别把性能优化放在哪些层面?默认情况下谁帮你做得更多?项目变复杂后,开发者需要掌握哪些优化手段?哪些问题是框架机制带来的,哪些只是代码写法问题?

Vue 3 和 React 都足够快,但它们的优化路径不同。Vue 3 倾向于结合响应式系统和模板编译做更细粒度的更新提示。React 倾向于通过重新执行组件得到下一份 UI,再通过协调过程和开发者控制边界来优化。

一、Vue 3 的默认优化:响应式依赖加模板编译

Vue 3 的性能基础有两层:响应式系统和模板编译。

响应式系统负责知道哪些状态被读取,状态变化后触发相关更新。模板编译器则把模板编译成渲染函数,并在编译阶段标记静态内容和动态部分。Vue 官方渲染机制文档提到,Vue 会使用静态提升、patch flag、树结构打平等方式减少运行时需要处理的内容。

用更通俗的话说,Vue 模板不是运行时才完全摸黑分析。因为模板语法受控,编译器能提前看出哪些地方永远不变,哪些地方只有文本变,哪些地方 class 或 props 变。运行时更新时,Vue 不必对所有节点都做同样成本的检查。

比如一个模板里有大段静态结构:

代码语言:vue
复制
<template>
  <article>
    <header>
      <h1>用户详情</h1>
      <p>这里是固定说明文案</p>
    </header>
    <section>{{ user.name }}</section>
  </article>
</template>

Vue 可以识别静态部分,把更新重点放在动态文本上。开发者不需要手动给这段静态 header 做缓存。

这就是 Vue 默认体验的优势。业务开发者按常规模板写,框架和编译器会自动做一部分优化。不是说你完全不用关心性能,而是很多普通页面不需要上来就考虑 memo。

二、React 的默认模型:重新执行组件函数

React 函数组件更新时,会重新执行组件函数,得到新的 JSX。React 再对比新旧结果,并把必要变化提交到 DOM。

这套模型非常简单:UI 是状态的函数。状态变了,函数重新执行,React 计算下一份 UI。简单带来可预测性,也带来一个常见问题:父组件更新时,子组件函数通常也会跟着重新执行,除非你做了边界控制。

例如:

代码语言:jsx
复制
function Parent() {
  const [count, setCount] = useState(0)

  return (
    <>
      <button onClick={() => setCount(count + 1)}>{count}</button>
      <ExpensiveChild />
    </>
  )
}

count 更新时,Parent 重新执行,ExpensiveChild 也会被重新渲染计算。最终真实 DOM 不一定大量变化,但组件函数执行本身可能有成本。如果 ExpensiveChild 很重,就需要考虑 memo、组件拆分、状态下沉、children 组合等优化方式。

React 的优势是模型统一,优化边界清晰。你可以用 React.memo 缓存组件结果,用 useMemo 缓存计算结果,用 useCallback 缓存函数引用。但这些工具也有成本。滥用 memo 不一定提升性能,反而让代码更难读。

三、Vue 的细粒度不等于永远不用优化

有些人会说 Vue 是细粒度响应式,所以性能不用管。这个说法不准确。

Vue 的响应式确实能减少一些无关更新,但组件仍然会有渲染成本。一个大组件里读取了很多响应式状态,只要相关依赖变化,组件渲染函数仍然要执行。大量列表、复杂计算、深层响应式对象、频繁 watch、副作用里同步重活,都会造成性能问题。

Vue 项目里常见优化包括:

  • 使用 computed 缓存派生值,而不是在模板里反复执行重计算。
  • 大列表使用虚拟滚动,不要一次渲染几千上万 DOM 节点。
  • 合理拆分组件,避免一个巨型组件承担所有更新。
  • 使用 v-memov-once 优化特定稳定区域。
  • 对不需要深层响应式的大对象使用 shallowRefshallowReactivemarkRaw
  • 保持 key 稳定,避免列表 diff 错误或过度重建。

Vue 提供了不少优化工具,但前提是你知道瓶颈在哪里。没有测量就盲目优化,往往只是增加复杂度。

四、React 的 memo 不是性能银弹

React 项目里,memouseMemouseCallback 经常被误用。

React.memo 可以在 props 没变化时跳过组件重新渲染。但如果你每次都传新的对象或函数,它就很难发挥作用:

代码语言:jsx
复制
<Child options={{ size: 'small' }} onClick={() => save()} />

这里 optionsonClick 每次渲染都是新引用,即使内容一样,浅比较也会认为变了。于是很多人开始加 useMemouseCallback

代码语言:jsx
复制
const options = useMemo(() => ({ size: 'small' }), [])
const handleClick = useCallback(() => save(), [save])

这在某些场景有效,但不是所有地方都值得做。缓存本身也有开销,还会增加依赖数组维护成本。如果组件很轻,重新渲染并不贵,memo 反而让代码变复杂。

React 的优化重点不应该是“看到函数就 useCallback”。更好的策略是先让状态位置合理。某个状态只影响局部,就不要放到很高的父组件里。某个昂贵子树不依赖变化状态,可以通过组件拆分、children 传入或 memo 控制边界。只有确认渲染成本明显时,再做精确缓存。

五、列表渲染:key 在两边都很重要

Vue 和 React 都需要稳定 key。很多性能和状态错乱问题,最后都能追到 key 上。

Vue:

代码语言:vue
复制
<li v-for="user in users" :key="user.id">
  {{ user.name }}
</li>

React:

代码语言:jsx
复制
{users.map(user => (
  <li key={user.id}>{user.name}</li>
))}

不要随便用数组下标当 key,尤其是列表会排序、插入、删除时。下标 key 可能导致组件状态错位,也会影响 diff 质量。稳定业务 ID 是更好的选择。

大列表问题也不是框架 diff 能完全解决的。真实 DOM 数量太多,浏览器布局、绘制、内存都会变重。无论 Vue 还是 React,几千行复杂列表都应该考虑虚拟滚动、分页、懒加载、窗口化渲染。

六、计算缓存:Vue computed 和 React useMemo 的差异

Vue 的 computed 是响应式系统里的缓存派生值。它会根据依赖自动失效:

代码语言:js
复制
const visibleUsers = computed(() => {
  return users.value.filter(user => user.visible)
})

只要 users.value 没有变化,visibleUsers 不会重复计算。模板读取它时也能拿到缓存结果。

React 的 useMemo 是在组件渲染过程中缓存某个计算结果:

代码语言:jsx
复制
const visibleUsers = useMemo(() => {
  return users.filter(user => user.visible)
}, [users])

它依赖开发者维护依赖数组。users 引用不变时返回缓存,引用变化时重新计算。

两者都能缓存计算,但 Vue 的 computed 更像响应式派生状态,React 的 useMemo 更像渲染期间的性能提示。React 官方也提醒过,不应该把 useMemo 当作语义保证;代码不应该依赖它才能正确,只应该把它作为优化手段。

七、打包和加载性能:框架之外更重要

很多用户感知到的慢,不是点击按钮后框架更新慢,而是首屏慢、资源大、接口慢、图片未优化、第三方库太重。

Vue 和 React 都可以配合 Vite、Rollup、webpack、ESBuild、SWC 等工具优化打包。也都支持代码分割、懒加载、路由级拆包。具体项目中,首屏性能更多取决于你是否合理拆包、是否延迟加载非关键模块、是否压缩图片、是否减少阻塞脚本、是否处理缓存策略。

如果应用用了 SSR 或 SSG,还要考虑服务端渲染成本、hydration 成本、流式渲染、边缘缓存等问题。React 生态里的 Next.js、Remix,Vue 生态里的 Nuxt 都在解决这些更高层的问题。单独比较 Vue 和 React 核心库的更新性能,并不能代表完整应用体验。

八、实践建议

Vue 项目里,先相信默认优化,不要过早上复杂技巧。模板里避免重计算,派生数据用 computed。列表 key 稳定,大列表用虚拟滚动。大型不可变数据或第三方实例不要盲目 deep reactive。性能问题出现后,用 Vue Devtools 和浏览器 Performance 面板定位,再决定是否使用 v-memoshallowRef、组件拆分等手段。

React 项目里,先把状态放对位置。不要把局部状态提到全局,也不要让一个父组件掌控所有变化。昂贵组件再考虑 memo,昂贵计算再考虑 useMemo,需要稳定传给 memo 子组件的函数再考虑 useCallback。不要为了“看起来专业”全项目铺满缓存。React 性能优化的第一原则是减少不必要的更新范围,而不是机械加 API。

九、结论:Vue 默认帮你多做一点,React 要你更主动管理边界

Vue 3 的性能路线是响应式追踪加模板编译优化,默认情况下对业务页面比较友好。React 的性能路线是状态更新后重新计算 UI,再通过组件边界和缓存工具控制成本。Vue 不是不用优化,React 也不是性能差;它们只是把优化责任分配得不同。

如果团队希望框架和编译器默认兜住更多常规场景,Vue 会显得更省心。如果团队擅长组件边界设计,能够合理使用 memo 和状态拆分,React 可以支撑非常复杂的 UI。

真正专业的性能判断,不是问谁更快,而是先测量,再定位,再选择最小代价的优化方式。

代码补充:不要把优化 API 当装饰品

Vue 里如果一段内容只需要渲染一次,可以使用 v-once

代码语言:vue
复制
<template>
  <header v-once>
    <h1>系统管理后台</h1>
    <p>这段静态说明不会参与后续更新</p>
  </header>
</template>

如果列表项很多,但只有特定字段变化才需要更新,可以谨慎使用 v-memo

代码语言:vue
复制
<template>
  <UserRow
    v-for="user in users"
    :key="user.id"
    v-memo="[user.id, user.updatedAt]"
    :user="user"
  />
</template>

React 中,memo 适合包住确实昂贵、且 props 稳定的组件:

代码语言:jsx
复制
const UserRow = memo(function UserRow({ user, onSelect }) {
  return (
    <li onClick={() => onSelect(user.id)}>
      {user.name}
    </li>
  )
})

但如果父组件每次都创建新函数,memo 的效果会被削弱:

代码语言:jsx
复制
function UserList({ users }) {
  const handleSelect = useCallback(id => {
    console.log('select', id)
  }, [])

  return users.map(user => (
    <UserRow key={user.id} user={user} onSelect={handleSelect} />
  ))
}

更重要的是先减少更新范围。例如把输入框状态放在搜索区域内部,而不是放到整个页面顶层:

代码语言:jsx
复制
function Page() {
  return (
    <>
      <SearchBox />
      <ExpensiveDashboard />
    </>
  )
}

function SearchBox() {
  const [keyword, setKeyword] = useState('')
  return <input value={keyword} onChange={e => setKeyword(e.target.value)} />
}

这类拆分通常比盲目 memo 更有效。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、Vue 3 的默认优化:响应式依赖加模板编译
  • 二、React 的默认模型:重新执行组件函数
  • 三、Vue 的细粒度不等于永远不用优化
  • 四、React 的 memo 不是性能银弹
  • 五、列表渲染:key 在两边都很重要
  • 六、计算缓存:Vue computed 和 React useMemo 的差异
  • 七、打包和加载性能:框架之外更重要
  • 八、实践建议
  • 九、结论:Vue 默认帮你多做一点,React 要你更主动管理边界
  • 代码补充:不要把优化 API 当装饰品
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档