Vue3 响应式系统:`ref`/`reactive`/`watchEffect` 的工作方式与最佳实践

你写 Vue3 时经常会遇到这些"似懂非懂"的问题:

  • 为什么 ref 需要 .value
  • 为什么 reactive 解构后就"不响应"了?
  • watchwatchEffectcomputed 到底怎么选?

这篇不从源码堆概念,而是用"你在项目里一定会踩的坑"为主线,把 Vue3 响应式讲清楚。


1. 响应式的目标是什么

目标只有一个:

  • 当某个状态发生变化时,能定位到"谁用到了它",并触发对应的更新。

对应两个关键动作:

  • 依赖收集:谁在读取这个状态?
  • 派发更新:这个状态变了,要通知谁重新执行?

Vue3 用 Proxy/Reflect + effect(副作用函数)完成这件事。


2. reactive:对象的响应式

reactive(obj) 返回一个 Proxy:

  • 读取属性(get)时:收集依赖
  • 修改属性(set)时:触发更新

适合:

  • 状态本身是一个对象/数组
  • 需要深层属性自然响应

2.1 常见坑:解构丢响应

js 复制代码
const state = reactive({ count: 0 })
const { count } = state
count++ // 这里不会触发视图更新

原因:解构得到的是一个普通值,不再经过 Proxy 的 get

解决:

  • toRefs(state) / toRef(state, 'count')
js 复制代码
import { reactive, toRefs } from 'vue'

const state = reactive({ count: 0 })
const { count } = toRefs(state)
count.value++

3. ref:单值/原始类型的响应式

ref(0) 返回形如 { value: 0 } 的对象,它本身也会被响应式处理。

为什么要有 .value

  • 为了让原始类型也能用同一套"依赖收集/触发更新"的机制

适合:

  • 数字/字符串/布尔值等原始类型
  • 你希望"一个变量就是一个状态"

3.1 ref 包对象会怎样

js 复制代码
const user = ref({ name: 'a' })
user.value.name = 'b' // 也能响应

本质上:ref 内部会把对象也做成响应式(类似 reactive)。


4. computed:带缓存的派生状态

特点:

  • 懒执行:没人读就不算
  • 有缓存:依赖不变不重新算

适合:

  • 由多个状态推导出的展示字段
  • 避免把"计算逻辑"散落在模板里

5. watch vs watchEffect

5.1 watch

  • 你明确知道要监听谁(source)
  • 你需要 old/new
  • 你需要精细控制(immediate / deep / flush)
js 复制代码
watch(
  () => state.keyword,
  (newVal, oldVal) => {
    fetchList(newVal)
  },
  { immediate: true }
)

5.2 watchEffect

  • 你不想声明 source
  • 只要 effect 内读取到的响应式数据变化,就重新执行
js 复制代码
watchEffect(() => {
  fetchList(state.keyword)
})

注意:watchEffect 很方便,但也更容易"无意间读到多余依赖"导致频繁触发。


6. 实战建议(项目里最实用的选择策略)

  • 状态是对象/表单 :优先 reactive,配合 toRefs 暴露字段
  • 状态是单值 :优先 ref
  • 派生展示字段 :用 computed
  • 请求联动 :优先 watch(能控粒度、能拿 old/new、好排查)
  • 自动收集依赖的副作用 :再用 watchEffect

7. 常见坑与排查

  • 响应式失效 :优先检查"是否解构了 reactive"
  • watch 不触发 :检查 source 是否是 getter(watch(() => obj.x, ...)
  • 频繁触发 :检查 watchEffect 内是否读取了多余状态

8. 总结

  • Vue3 响应式核心是:依赖收集 + 派发更新
  • reactive 适合对象,但解构会丢响应,需要 toRefs
  • ref 让原始类型也能响应式
  • computed 做派生字段,带缓存
  • watch 更可控,watchEffect 更省事但更容易过度依赖
相关推荐
donecoding36 分钟前
一个 sudo 引发的血案:npm 全局包权限错乱彻底修复
前端·node.js·前端工程化
风骏时光牛马41 分钟前
Raku正则匹配与数据批量处理实操案例
前端
nbwenren44 分钟前
2026实测:Gemini 3 镜像站视觉能力实践——拍照原型图,一键生成 HTML+CSS 代码
前端·css·html
Lee川1 小时前
Prisma 实战指南:像搭积木一样设计古诗词数据库
前端·数据库·后端
jinanwuhuaguo1 小时前
(第二十九篇)OpenClaw 实时与具身的跃迁——从异步孤岛到数字世界的“原住民”
前端·网络·人工智能·重构·openclaw
广州华水科技1 小时前
深度测评2026年单北斗GNSS位移监测系统推荐,与高口碑变形监测设备一同引领行业新风尚
前端
Alice-YUE2 小时前
【js高频八股】防抖与节流
开发语言·前端·javascript·笔记·学习·ecmascript
是上好佳佳佳呀3 小时前
【前端(十一)】JavaScript 语法基础笔记(多语言对比)
前端·javascript·笔记
CDN3604 小时前
排查实录:网站偶发502/504错误?360CDN回源超时配置与日志分析技巧
前端·数据库