ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

vue和react的响应式有什么区别?(上)

2026/8/16 2:09:06 拓冰建站 浏览量
vue和react的响应式有什么区别?(上)

Vue 和 React 都能做到“数据变化后更新页面”,但它们感知变化的方式不同:

Vue 追踪“哪些响应式属性被读取和修改”;React 追踪“哪个组件调用了状态更新函数”。

可以先看这张核心对比表:

一、React:显式通知式响应

React 不会监听普通变量或对象属性的修改。

function Counter() { let count = 0 function add() { count++ } return <button onClick={add}>{count}</button> }

点击以后,变量确实变了,但页面不会更新,因为 React 不知道发生了变化。

必须调用 React 提供的 setter:

function Counter() { const [count, setCount] = useState(0) function add() { setCount(count + 1) } return <button onClick={add}>{count}</button> }

setCount做两件事:

记录下一次状态 + 请求 React 重新渲染当前组件

下一次渲染时,React 会重新调用Counter(),生成新的 JSX,再把新旧结果进行协调比较。React 官方将这一过程划分为触发渲染、执行渲染和提交 DOM 三个阶段。

可以简化成:

setCount(1) ↓ React 安排更新 ↓ Counter() 再执行一次 ↓ 得到新的 JSX ↓ 比较新旧 UI ↓ 更新必要的 DOM

二、Vue:依赖追踪式响应

Vue 会把状态转换成响应式对象:

import { reactive } from 'vue' const state = reactive({ count: 0 })

Vue 3 对响应式对象主要使用Proxy。简化原理如下:

function reactive(obj) { return new Proxy(obj, { get(target, key) { track(target, key) return target[key] }, set(target, key, value) { target[key] = value trigger(target, key) return true } }) }

当组件渲染时读取:

state.count

Vue 的get拦截器会记录:

当前组件依赖 state.count

以后执行:

state.count++

set拦截器会通知之前依赖state.count的响应式 effect,组件随后重新渲染。Vue 3 对响应式对象使用 Proxy,对ref.value使用 getter/setter,并通过tracktrigger完成依赖收集及更新触发。

过程可以简化为:

组件读取 state.count ↓ Vue 记录依赖关系 ↓ state.count++ ↓ Proxy 拦截修改 ↓ 通知依赖它的组件 ↓ 组件重新渲染

三、最大的区别:谁负责告诉框架发生了变化

React:开发者显式通知

setCount(count + 1)

React 不关心你之前读取了哪些普通变量。它只知道:

某个 state setter 被调用了 当前组件需要重新计算

Vue:框架自动追踪

count.value++

或者:

state.count++

Vue在组件渲染过程中已经记录了:

这个组件读取过 count

所以 count 修改后,它知道应该通知哪些响应式 effect。

因此可以概括为:

React:事件驱动组件更新 Vue:依赖驱动组件更新

不过两者最后通常都会重新执行相应组件的渲染逻辑,并同步必要的 DOM 变化。

四、对象更新方式不同

这是实际开发中最明显的区别之一。

Vue 可以直接修改响应式对象

<script setup> import { reactive } from 'vue' const user = reactive({ name: 'Alice', age: 20 }) function rename() { user.name = 'Bob' } </script> <template> <button @click="rename"> {{ user.name }} </button> </template>

执行:

user.name = 'Bob'

会经过 Proxy 的set拦截,因此可以触发更新。

React 通常不能直接修改状态对象

错误写法:

const [user, setUser] = useState({ name: 'Alice', age: 20 }) function rename() { user.name = 'Bob' setUser(user) }

这里传回去的仍然是原来的对象:

Object.is(oldUser, newUser) // true

React 可能认为状态没有变化并跳过更新。

应创建新对象:

function rename() { setUser(previous => ({ ...previous, name: 'Bob' })) }

React 官方建议把 state 中的对象视为只读数据,通过创建并传入新对象完成更新,而不是直接修改原对象

所以:

Vue:以可变响应式对象为主 React:以状态快照和不可变更新为主

五、更新粒度有什么区别

假设状态是:

const state = { name: 'Alice', age: 20, address: { city: 'Beijing' } }

Vue 的依赖追踪更细

如果模板只读取:

<p>{{ state.name }}</p>

Vue 会追踪对state.name的读取。

修改:

state.age++

不会触发所有读取state的响应式逻辑;Vue知道修改的是age,而不是name

但要注意:

Vue知道哪些属性触发了组件的渲染 effect,不代表它直接绕过组件重新渲染、只修改一个表达式。

当前 Vue 默认渲染系统仍会重新执行相关组件的渲染 effect,然后借助虚拟 DOM 和编译器生成的优化信息减少比较及 DOM 操作。

React 的触发单位更偏向组件

const [user, setUser] = useState({ name: 'Alice', age: 20 })

调用:

setUser(previous => ({ ...previous, age: previous.age + 1 }))

React知道的是:

这个组件的 user 状态更新了