Vue vs React 响应式原理详解
在前端框架的世界里,“响应式”是核心能力之一。它让数据状态的变化能够驱动视图自动更新,省去手动操作 DOM 的繁琐。虽然 Vue 和 React 都实现了响应式,但底层机制有明显差异。
一、Vue 的响应式机制
1. Vue 2:Object.defineProperty 数据劫持
- 初始化时,对
data对象的每个属性使用Object.defineProperty定义 getter/setter。 - 访问属性时触发 依赖收集(记录哪些地方用到了这个属性)。
- 修改属性时触发 派发更新(精准通知用到该属性的组件更新)。
示例:
let data = { count: 0 };
Object.defineProperty(data, "count", {
get() { console.log("get count"); return value; },
set(newVal) { console.log("set count", newVal); /* 通知更新 */ }
});
优点:
- 更新粒度小,性能高。
- 修改属性会直接触发更新。
缺点:
- 无法监听对象新增属性、数组索引变化(需使用
Vue.set)。 - 初始化时需要遍历所有属性,存在性能成本。
2. Vue 3:Proxy 全面代理
- 使用 ES6
Proxy一次性拦截对象的所有操作(读写、删除、属性新增等)。 - 无需像 Vue 2 一样递归遍历属性。
- 更灵活,能监听 Map、Set 等复杂数据结构。
优点:
- 能监听对象新增/删除属性。
- 支持更多数据结构。
- 初始化性能更好。
二、React 的响应式机制
React 并不使用数据劫持,而是采用 状态驱动 + Virtual DOM 的理念。
核心流程
- 数据(state)改变时,通过
setState或useState触发更新。 - React 会让组件 重新执行函数(函数组件)或 调用 render 方法(类组件)。
- 生成新的 Virtual DOM,和旧的 Virtual DOM 进行 Diff 比较。
- 找出差异并批量更新到真实 DOM。
示例:
const [count, setCount] = useState(0);
<button onClick={() => setCount(count + 1)}>+1</button>
优点:
- 实现简单,心智模型清晰(UI = f(state))。
- 没有属性监听的限制,数据结构自由。
缺点:
- 更新是以组件为单位,可能会多渲染无关部分(可用
memo优化)。 - 依赖 Virtual DOM diff,更新路径可能比 Vue 粗。
三、对比分析
| 特性 | Vue 2 | Vue 3 | React |
|---|---|---|---|
| 响应式方式 | defineProperty 数据劫持 | Proxy 全代理 | 状态驱动(setState/useState) |
| 更新粒度 | 精确到属性 | 精确到属性 | 精确到组件 |
| 新增属性监听 | ❌(需 Vue.set) | ✅ | ✅(重新渲染) |
| 初始化性能 | 遍历所有属性 | 一次性代理 | 不监听,依赖状态更新 |
| 数据结构支持 | 对象、数组(有限制) | 对象、数组、Map、Set 等 | 任意 |
四、场景建议
- 如果你想要精准更新、依赖收集、性能敏感场景 → Vue 更适合。
- 如果你更倾向状态驱动、函数式 UI、组件自由组合 → React 是好选择。
- 现代 Vue 3 和 React Concurrent Mode 在性能上的差距已经不大,更多是开发体验和生态的选择。