巨蛋乐园
29.11M · 2026-03-22
十年前我们还在用 jQuery 手动操作 DOM。
$('#btn').click() 写多了,代码就像意大利面条。后来 Angular 带来了 MVC,React 带来了 Virtual DOM,Vue 把响应式做到了极致。
现在回头看,React 和 Vue 其实代表了两种完全不同的架构思路。理解它们的分歧点,比纠结"哪个更好"更有价值。
React 的设计理念很简单:开发者知道什么时候该更新。
function Counter() {
const [count, setCount] = useState(0);
// 你必须显式调用 setCount
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
React 的渲染是"全量"的。每次状态变化,组件函数重新执行,返回新的 JSX。React 再对比新旧 Virtual DOM,算出最小变更。
这种方式的好处是可预测。你写的代码就是执行的逻辑,没有黑魔法。
坏处也明显:优化负担在开发者身上。useMemo、useCallback、React.memo 缺一不可,稍不注意就重复渲染。
Vue 的想法相反:框架比开发者更清楚依赖关系。
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<button @click="count++">{{ count }}</button>
</template>
Vue 在编译阶段就分析好了模板中的依赖。count 变化时,框架自动定位到具体 DOM 节点,直接更新。
不需要你记一堆优化规则。响应式系统帮你搞定。
| 维度 | React | Vue |
|---|---|---|
| 更新粒度 | 组件级 | 细粒度(变量级) |
| 优化责任 | 开发者 | 框架 |
| 心智模型 | 显式控制 | 自动追踪 |
| 代码风格 | 函数式 | 声明式 |
这两个词听起来很抽象,但本质是怎么知道"数据变了"。
React 是 Pull。它不会数据变化,而是在渲染时拉取最新值。
function User({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser(userId).then(setUser);
}, [userId]); // 依赖数组靠人工维护
return <div>{user?.name}</div>;
}
这里有个坑:如果忘了写 [userId],就拿到旧数据。如果写了 [user],就无限循环。
React 的依赖数组是信任开发者。你说没依赖,它就信。
React Compiler 在 2025 年底已经稳定发布。Compiler 能自动推导依赖,不用再手写 useMemo/useCallback。
Vue 是 Push。数据变化主动推送给订阅者。
<script setup>
import { ref, watchEffect } from 'vue'
const userId = ref(1)
const user = ref(null)
// 自动追踪 userId 的依赖
watchEffect(async () => {
user.value = await fetchUser(userId.value)
})
</script>
watchEffect 会自动收集用到的响应式变量。userId 一变,回调重新执行。
不需要依赖数组。框架帮你追踪。
React 的依赖检测在运行时。每次渲染对比上一次的状态。
Vue 的依赖检测在编译时 + 运行时。编译阶段标记响应式变量,运行时通过 Proxy 拦截访问和修改。
// Vue 响应式简化实现
function ref(value) {
const dep = new Set();
return new Proxy({ value }, {
get(target, key) {
// 收集当前活跃的 effect
if (activeEffect) dep.add(activeEffect);
return target[key];
},
set(target, key, newVal) {
target[key] = newVal;
// 通知所有订阅者
dep.forEach(effect => effect());
return true;
}
});
}
这套机制让 Vue 能做到精准更新。只有真正用到的数据变了,才会触发更新。
过去一年,两个框架的编译时优化都有了实质性进展。
2025年10月,React Compiler 1.0 正式发布。现在是 2026 年,它已经经过了生产环境的验证。
它是个 Babel 插件,编译阶段分析你的代码,自动插入 memoization。不用再手写 useMemo/useCallback。
// 以前
function List({ items }) {
const sorted = useMemo(() =>
items.sort((a, b) => b.score - a.score),
[items]
);
return <div>{sorted.map(...)}</div>;
}
// 有了 Compiler,直接写
function List({ items }) {
const sorted = items.sort((a, b) => b.score - a.score);
return <div>{sorted.map(...)}</div>;
}
Compiler 会把 sorted 编译成条件性 memoized 值。只有 items 真的变了,才重新计算。
实测效果:
这解决了 React 最大的痛点:优化负担太重。
Vue 的回应是 Vapor Mode。2025 年底它在 Vue 3.6 中作为实验性功能发布,现在(2026年3月)已经可以尝试使用。
Vapor Mode 的思路很激进:编译时直接生成 DOM 操作代码,跳过 Virtual DOM。
<template>
<div>{{ count }}</div>
<button @click="count++">+</button>
</template>
传统 Vue:编译成 Virtual DOM → 运行时 diff → patch DOM
Vapor Mode:编译成直接的 DOM 操作代码
// Vapor Mode 编译结果示意
let _div, _btn;
export function render(_ctx) {
if (!_div) {
_div = document.createElement('div');
_btn = document.createElement('button');
_btn.onclick = () => _ctx.count++;
}
_div.textContent = _ctx.count;
return [_div, _btn];
}
没有 diff,没有 patch,直接操作 DOM。
性能数据:
Vapor Mode 支持混合模式:可以和现有 Virtual DOM 组件共存。你可以只对性能敏感的部分启用 Vapor Mode。
| 特性 | React Compiler | Vue Vapor Mode |
|---|---|---|
| 发布状态 | 2025.10 稳定版 | 2025 实验性,2026 可用 |
| 优化阶段 | 编译时 | 编译时 |
| 优化方式 | 自动 memoization | 消除 Virtual DOM |
| 向后兼容 | React 17+ | Vue 3 混合模式 |
| 限制 | 需遵循 React 规则 | 仅支持 Composition API |
2024-2025 年的 benchmark 数据:
Vue 在 DOM 操作任务上比 React 快 36%(几何平均 1.02 vs React)。
差距不大,都能接受。
性能不是主要差异点。两个框架都足够快。
真正的区别是优化方式:
没有标准答案,但有几个参考维度。
React Compiler 已经在生产环境证明了价值,优化负担不再是 React 的短板。Vue Vapor Mode 让 Vue 性能更进一步,两者差距在缩小。
两个框架都在进化,差距在缩小。
架构选择没有银弹。
React 给你控制权,代价是多写代码。Vue 帮你省代码,代价是接受框架的约束。
2026年,这两条路线已经收敛:React 变得更智能,Vue 变得更高效。
你现在的选择,不会让你后悔。重要的是深入理解你选的框架,而不是来回横跳。
毕竟,用户不关心你用什么框架。他们只关心产品好不好用。
参考来源:
文中性能数据来自 2024-2025 年公开 benchmark 报告。