Vue3 响应式革命

Vue2 验证了「响应式驱动视图」的威力,却在数组索引、属性增删等场景留下无法追踪的死角。Vue3 并未缝缝补补,而是把整座大厦的地基------数据拦截机制------彻底替换为 Proxy。本文沿着「拦截 → 创建 → 收集」三条链路,带你读懂这一次底层跃迁的全部细节。

一、拦截:从点到面的语义升级

1.Vue2 的「定点拦截」

Object.defineProperty 只能劫持已存在的属性。当业务代码 obj.newKey = 1 时,这条新增路径对依赖系统完全不可见,于是官方只能额外暴露 Vue.set / vm.$set 作为补丁。

2.Vue3 的「整面拦截」

Proxy 把「对象」视为一个整体,任何对属性的 读取、写入、删除、遍历 乃至 原型链读取 都能被捕获。

ts 复制代码
const p = new Proxy(obj, {
  get(target, key, receiver) { /* 读 */ },
  set(target, key, value, receiver) { /* 写 */ },
  deleteProperty(target, key) { /* 删 */ }
})

新增 key 不再逃逸,数组索引与 length 的变化自然落入监听范围,彻底告别 $set

二、创建:ref 与 reactive 的分工

虽然 Proxy 能力更强,但「原始值」无法被代理。Vue3 用 RefImpl 与 ReactiveImpl 两套实现互补:

  • ref 负责原始值(Number、String、Boolean)------内部用 RefImpl 包裹,读/写时触发自定义 getter/setter;当值是对象时再递归交给 reactive
  • reactive 负责对象/数组------直接返回 Proxy,拦截全部操作。

源码片段(精简):

ts 复制代码
class RefImpl<T> {
  get value() {
    track(this, 'value')   // 收集
    return this._value
  }
  set value(newVal) {
    this._value = toReactive(newVal)
    trigger(this, 'value') // 派发
  }
}

function reactive(target: object) {
  return createReactiveObject(target, mutableHandlers)
}

toReactive 判断传入值是否为对象,是则继续包 Proxy,否则原样返回,形成一条「层层代理,按需终止」的链。

三、收集:从 Watcher 树到副作用图

1.Vue2 的 Watcher + Dep

每个响应式属性拥有一个 Dep,Dep 里存着若干 Watcher(通常是一个组件渲染函数)。属性变化 → 通知所有 Watcher → 组件级重渲染。

粒度:组件级别。

2.Vue3 的副作用图

Vue3 不再关心「是哪个组件」,而是关心「哪个副作用函数」。数据结构是一张 WeakMap → Map → Set 的三级表:

  • 第一级 WeakMap:键是响应式对象,值是第二级 Map;
  • 第二级 Map:键是属性名,值是第三级 Set;
  • 第三级 Set:存储所有依赖该属性的 effect 函数。

当属性值改变时,只触发 精确到函数 的重新执行,粒度从组件级降到函数级,更新范围更小,性能更高。

四、工程实践的迁移

  • Vue2 项目:若观察到大量 this.$setVue.set,说明已踩中响应式盲区,升级 Vue3 可一次性消除。
  • 新 Vue3 项目:优先使用 reactive 管理对象,ref 管理原始值;避免把 reactive 包进 ref,防止双重代理带来的额外开销。
  • 性能调优:借助 markRawshallowReactive 把大列表、第三方库实例标记为非响应式,减少追踪压力。

结语

Vue3 的响应式不是「打补丁」,而是「换引擎」。Proxy 让「增删改查」全部可追踪,WeakMap 让依赖收集更精准。这次底层跃迁,彻底解决了 Vue2 的响应式难题,也为 Vue3 的性能优化奠定了基础。

相关推荐
Rysxt_29 分钟前
Vue文件下载功能完整指南:从基础实现到进阶实战
前端·javascript·vue.js
一 乐39 分钟前
智慧养老|基于springboot+小程序社区养老保障系统设计与实现(源码+数据库+文档)
java·前端·数据库·vue.js·spring boot·后端·小程序
冰暮流星41 分钟前
css3网格布局2
前端·css·css3
JIseven1 小时前
uniapp页面新手引导
java·前端·uni-app
烛阴1 小时前
代码的“病历本”:深入解读C#常见异常
前端·c#
努力学算法的蒟蒻1 小时前
day26(12.6)——leetcode面试经典150
算法·leetcode·面试
IT_陈寒1 小时前
Python 3.12 新特性实战:10个提升开发效率的隐藏技巧大揭秘
前端·人工智能·后端
老华带你飞2 小时前
旅游|基于Java旅游信息推荐系统(源码+数据库+文档)
java·开发语言·数据库·vue.js·spring boot·后端·旅游
dangdang___go2 小时前
文件操作2+程序的编译和链接(1)
java·服务器·前端