Vue响应式系统

Vue3 如何通过响应式状态驱动视图与副作用更新。

#tech / dev / frame #resource / vue3 #type / concept #status / growing

[!info] related notes

Vue响应式系统

Vue 响应式系统的目标是:当状态变化时,让依赖该状态的模板、计算结果和副作用自动更新。

一句话定义

响应式不是“自动刷新页面”这么简单,而是 Vue 把“数据变化”和“依赖更新”建立成了一套可追踪的关系。

和 React 最大的直觉差异

如果你同时学 React 和 Vue,这里最值得抓住的差异是:

  • React 更强调“组件重新执行 + Hook 顺序 + 显式依赖”
  • Vue 更强调“响应式依赖收集 + 值变化驱动依赖重新计算”

所以 Vue 里很多体验会更像:

  • 你声明一个响应式来源
  • 依赖它的计算和副作用自动知道自己依赖了什么

而 React 里则更常需要你显式管理:

  • state 放哪
  • effect 依赖写什么
  • 哪些引用需要稳定

Vue3 为什么改用 Proxy

  • Vue2 主要依赖 Object.defineProperty
  • Vue3 改用 Proxy 代理整个对象
  • 这样可以更自然地监听属性新增、删除、数组变化和更复杂的数据结构

最常用的 5 个响应式 API

ref

适合表示单个响应式值,尤其是基本类型。

const count = ref(0)
count.value++

reactive

适合表示结构化对象状态。

const state = reactive({
  count: 0,
  user: { name: 'Tom' },
})

computed

用于表达派生状态,而不是重复存储结果。

watch

显式监听某个来源,适合在值变化后执行副作用。

watchEffect

自动收集依赖,适合快速声明一段响应式副作用。

如果要分别看边界和选型,继续读:

最重要的两个边界

派生值优先用 computed

如果一个值可以由其他状态推导出来,就不要再额外存一份。

副作用才用 watch / watchEffect

如果只是为了渲染结果,不要把本该用 computed 表达的逻辑塞进侦听器。

一个更体系化的理解

可以先把 Vue 响应式系统拆成三层:

  • 状态来源:ref / reactive
  • 派生结果:computed
  • 副作用响应:watch / watchEffect

这和 React 里:

  • useState
  • 渲染期派生 / useMemo
  • useEffect

在问题分层上是相似的,但运行机制不同。

refreactive 怎么选

  • 基本类型优先 ref
  • 表单对象、页面状态对象常用 reactive
  • 需要整体替换对象时,ref({}) 往往更灵活

常见误区

  • 在 JS 中忘记访问 ref.value
  • 用侦听器保存本来可以直接推导的派生结果
  • 在模板里写过重表达式,而不是提取到 computed
  • 以为响应式等于立即同步更新 DOM,忽略了批量更新与 nextTick

最短记忆方式

  • ref / reactive:保存状态
  • computed:解释状态
  • watch / watchEffect:响应状态变化后的副作用
创建于 2026/3/19 更新于 2026/5/27