vue3中的响应式系统是如何工作的

128 阅读4分钟

vue3中的响应式系统是如何工作的

Vue 3 的响应式系统是其核心机制,它通过 Proxy依赖收集 实现了数据的自动追踪与更新。相比 Vue 2 的 Object.defineProperty,Vue 3 的响应式系统更加高效且功能更强大。以下是其工作原理的详细解析:

  1. 核心机制:Proxy 与 Reflect

Vue 3 使用 Proxy 对象来拦截对数据的操作(如读取、修改、删除等),并通过 Reflect 完成默认行为。这种设计可以监听对象和数组的所有操作,而无需像 Vue 2 那样递归遍历对象属性。

const rawData = { count: 0 };
const reactiveData = new Proxy(rawData, {
  get(target, key, receiver) {
    track(target, key); // 依赖收集
    return Reflect.get(target, key, receiver);
  },
  set(target, key, value, receiver) {
    const result = Reflect.set(target, key, value, receiver);
    trigger(target, key); // 触发更新
    return result;
  },
  deleteProperty(target, key) {
    const result = Reflect.deleteProperty(target, key);
    trigger(target, key); // 触发更新
    return result;
  },
});
  1. 依赖收集与触发更新

响应式系统通过 依赖收集(Track)触发更新(Trigger) 实现数据与视图的关联。

2.1 依赖收集(Track)

  • 当访问响应式对象的属性时,Proxy 的 get 拦截器会调用 track 函数。

  • track 会将当前正在运行的 副作用函数(Effect)(如组件的渲染函数)与该属性关联起来。

2.2 触发更新(Trigger)

  • 当修改响应式对象的属性时,Proxy 的 set 拦截器会调用 trigger 函数。

  • trigger 会找到所有与该属性关联的副作用函数,并重新执行它们。

  1. 副作用函数(Effect)

副作用函数是响应式系统的核心执行单元,通常指组件的渲染函数或用户定义的 watch/computed

import { effect } from 'vue';

const data = reactive({ count: 0 });

// 定义一个副作用函数
effect(() => {
  console.log(`Count changed: ${data.count}`);
});

data.count++; // 触发 effect 重新执行,输出 "Count changed: 1"
  1. 响应式 API

Vue 3 提供了多种创建响应式数据的 API,适用于不同场景:

4.1 reactive

  • 用于创建对象和数组的深度响应式代理。

  • 内部基于 Proxy 实现。

import { reactive } from 'vue';

const obj = reactive({ a: 1, b: { c: 2 } });
obj.b.c = 3; // 触发更新

4.2 ref

  • 用于包装基本类型值(如 numberstring)或对象。

  • 通过 .value 访问或修改值。

  • 内部将基本类型转为 { value: ... } 对象,再使用 Proxy 代理。

import { ref } from 'vue';

const count = ref(0);
count.value++; // 触发更新

4.3 computed

  • 基于响应式数据生成计算属性。

  • 结果会被缓存,只有依赖变化时才重新计算。

import { ref, computed } from 'vue';

const count = ref(0);
const doubleCount = computed(() => count.value * 2);
  1. 响应式系统的关键流程

5.1初始化响应式对象

  • 使用 reactiveref 创建响应式数据。

5.2执行副作用函数

  • 组件渲染时,触发响应式数据的 get 拦截器。

  • 依赖收集系统记录当前副作用函数与数据的关联。

5.3数据修改触发更新

  • 修改数据时,触发 set 拦截器。

  • 依赖系统找到所有关联的副作用函数并重新执行。

  1. 优势与改进

6.1 相比 Vue 2 的改进

  • 全面拦截操作:Proxy 可以监听对象属性的添加、删除,以及数组的索引修改和 length 变化。

  • 性能优化:无需递归遍历对象属性,仅在访问时动态处理。

  • 支持更多数据结构:如 MapSetWeakMap 等(需结合 reactiveref)。

6.2 示例:监听数组变化

const list = reactive([1, 2, 3]);
list.push(4); // 触发更新
list[0] = 100; // 触发更新
  1. 响应式系统的局限性

7.1. 原始值需用 ref 包装

  • 基本类型(如 numberstring)必须通过 ref 转为响应式。

7.2. 深层响应式 vs 浅层响应式

  • reactive 默认递归代理对象的所有嵌套属性。

  • shallowReactiveshallowRef 可创建浅层响应式数据。

7.3. ES6 数据结构的处理

  • MapSet 等需结合 reactive 或手动处理。
  1. 工具函数

Vue 3 提供了一些辅助函数用于细粒度控制响应式:

  • markRaw:标记对象跳过代理。

  • toRaw:获取原始非响应式对象。

  • shallowReactive:仅代理对象的第一层属性。

  • shallowRef:仅跟踪 .value 的变化,不代理内部对象。

总结

Vue 3 的响应式系统通过 Proxy依赖收集 实现了高效的数据追踪:

  1. Proxy 拦截操作:监听数据的读取、修改和删除。

  2. 依赖收集与触发:通过 tracktrigger 关联数据与副作用函数。

  3. 响应式 APIreactiverefcomputed 等简化了响应式数据的管理。

  4. 性能优化:按需处理依赖,避免不必要的递归和更新。

这种机制使得 Vue 3 在处理复杂数据和大型应用时更加灵活和高效。

更多vue相关插件及后台管理模板可访问vue admin reference,代码详情请访问github