Skip to content

React 与 Vue 正在变成同一个框架 ​

译注:本文翻译自 dev.to 作者 Nazar Boyko 的评论文章,原文链接见文末。作者自述并非长期一线前端开发者,观点带有个人观察色彩,请读者自行判断。

导语 ​

一位开发者最近遇到一个团队,正把项目从 Vue 重写到 React,理由是「Vue 跑得更慢」。追查后发现,问题出在 Vue 代码是生成出来的、且没有做优化。这件事让作者开始思考:React 和 Vue 之间那些被反复争论的差异,是否还成立?

三个经典差异点正在失效 ​

网上关于 React 与 Vue 的对比已经足够多,作者只列出三个最常被提及的方面(模板 vs JSX 属于口味问题,不在讨论范围):

ReactVue
虚拟 DOM有有
记忆化手动,靠 memo、useMemo、useCallback自动,通过响应式系统
重新渲染范围组件及其子组件,除非你手动阻止只渲染读取了变化状态的部分

作者认为,这张表里的每一行都已经过时或即将过时。React 现在提供了编译器,替你写记忆化代码;Vue 则即将完成一个编译模式,让任何选择加入的组件都能摆脱虚拟 DOM。两者从同一场老争论的两端出发,最终走到了大致相同的位置:用一个构建步骤算出哪些东西不需要重新运行。

这也是作者认为「React vs Vue」这个问题第一次不再是技术问题的原因。它们不是同一个框架,仍然存在分歧,但大家最常引用的三个论点,恰恰是正在消融的三个。

React 的记忆化搬进了构建流程 ​

React 的默认行为简单而直接。memo 文档用一句话概括:「React 通常会在父组件重新渲染时重新渲染子组件。」多年来,解决办法都是手动告诉 React 什么可以跳过。

原文给出了一个带搜索框和可选中行的商品列表示例。手动版本需要三个工具,其中两个必须成对使用:

  • memo 让行组件在 props 与上次相同时跳过渲染;
  • useCallback 让 onPick 在多次渲染间保持同一个函数引用——这一点很关键,因为一个新函数会被视为变化的 prop,悄悄让 memo 失效;
  • useMemo 则用于避免在只有 picked 变化时重新执行过滤。

React 团队在 2024 年 2 月的 React Labs 文章中直言:「手动记忆化是一种妥协。它让代码变得杂乱,容易出错,还需要额外的工作来保持更新。」

React Compiler 1.0 于 2025 年 10 月发布,支持 React 17 及以上版本。官方发布文章建议新代码「依赖编译器进行记忆化,并在需要精确控制时使用 useMemo/useCallback」。Expo 自 SDK 54 起默认开启;Next.js 16 将 reactCompiler 选项转为稳定,但默认关闭,以便团队收集构建性能数据——官方也提醒开启后构建会变慢,因为编译器要跑 Babel,而运行在 Turbopack 内的 Rust 移植版直到 2026 年 8 月的 Next.js 16.3 才作为实验性开关出现。

也就是说,「React 现在替你记忆化」是真的,但有个脚注:在最流行的 React 框架上,仍然需要有人先去打开开关。

开启编译器后的 React 组件,就是把手动版本里所有包装器删掉;而 Vue 版本从来就没有包装器可删。

编译器会写你的 useCallback,但不一定写 useMemo ​

作者把那个朴素的 React 文件跑了一遍 babel-plugin-react-compiler 1.0.0,想看看实际产物而非示意图。结果是大量的簿记工作:ProductList 得到 21 个缓存槽,ProductRow 自己有 6 个,每一个都是普通数组项,用 if 判断。

原文展示了编译后代码的片段,可以看到 _c(21) 这样的调用,以及形如 if ($[0] !== picked || $[1] !== products || $[2] !== query) 的缓存检查。

结语 ​

作者强调,这篇文章不是要宣布两个框架已经合并。它们仍有分歧,但那些被反复拿来争论的技术差异点,正在被各自的编译器与编译模式同时抹平。当「谁更快」「谁需要手动优化」不再成立时,React 与 Vue 的选择可能更多取决于团队习惯与生态,而非性能叙事。

原文链接 ​

https://dev.to/nazar-boyko/react-and-vue-are-turning-into-the-same-framework-2aph