vue3中的响应式系统是如何工作的
Vue 3 的响应式系统是其核心机制,它通过 Proxy 和 依赖收集 实现了数据的自动追踪与更新。相比 Vue 2 的 Object.defineProperty,Vue 3 的响应式系统更加高效且功能更强大。以下是其工作原理的详细解析:
- 核心机制: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;
},
});
- 依赖收集与触发更新
响应式系统通过 依赖收集(Track) 和 触发更新(Trigger) 实现数据与视图的关联。
2.1 依赖收集(Track)
-
当访问响应式对象的属性时,Proxy 的
get拦截器会调用track函数。 -
track会将当前正在运行的 副作用函数(Effect)(如组件的渲染函数)与该属性关联起来。
2.2 触发更新(Trigger)
-
当修改响应式对象的属性时,Proxy 的
set拦截器会调用trigger函数。 -
trigger会找到所有与该属性关联的副作用函数,并重新执行它们。
- 副作用函数(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"
- 响应式 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
-
用于包装基本类型值(如
number、string)或对象。 -
通过
.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);
- 响应式系统的关键流程
5.1初始化响应式对象:
- 使用
reactive或ref创建响应式数据。
5.2执行副作用函数:
-
组件渲染时,触发响应式数据的
get拦截器。 -
依赖收集系统记录当前副作用函数与数据的关联。
5.3数据修改触发更新:
-
修改数据时,触发
set拦截器。 -
依赖系统找到所有关联的副作用函数并重新执行。
- 优势与改进
6.1 相比 Vue 2 的改进
-
全面拦截操作:Proxy 可以监听对象属性的添加、删除,以及数组的索引修改和
length变化。 -
性能优化:无需递归遍历对象属性,仅在访问时动态处理。
-
支持更多数据结构:如
Map、Set、WeakMap等(需结合reactive或ref)。
6.2 示例:监听数组变化
const list = reactive([1, 2, 3]);
list.push(4); // 触发更新
list[0] = 100; // 触发更新
- 响应式系统的局限性
7.1. 原始值需用 ref 包装:
- 基本类型(如
number、string)必须通过ref转为响应式。
7.2. 深层响应式 vs 浅层响应式:
-
reactive默认递归代理对象的所有嵌套属性。 -
shallowReactive或shallowRef可创建浅层响应式数据。
7.3. ES6 数据结构的处理:
Map、Set等需结合reactive或手动处理。
- 工具函数
Vue 3 提供了一些辅助函数用于细粒度控制响应式:
-
markRaw:标记对象跳过代理。 -
toRaw:获取原始非响应式对象。 -
shallowReactive:仅代理对象的第一层属性。 -
shallowRef:仅跟踪.value的变化,不代理内部对象。
总结
Vue 3 的响应式系统通过 Proxy 和 依赖收集 实现了高效的数据追踪:
-
Proxy 拦截操作:监听数据的读取、修改和删除。
-
依赖收集与触发:通过
track和trigger关联数据与副作用函数。 -
响应式 API:
reactive、ref、computed等简化了响应式数据的管理。 -
性能优化:按需处理依赖,避免不必要的递归和更新。
这种机制使得 Vue 3 在处理复杂数据和大型应用时更加灵活和高效。
更多vue相关插件及后台管理模板可访问vue admin reference,代码详情请访问github