Vue3-06 深入响应式原理

Vue3学习笔记-06 深入响应式原理

Vue如何追踪变化

Vue会使用带有Getter和Stter的处理程序遍历所有Property并将其转换为Proxy(使用Object.defineProperty来支持IE浏览器)。

Proxy是一个包含另一个对象或函数,并且允许你对其进行拦截的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const dinner = {
meal: 'tacos'
}

const handler = {
get(target, prop, receiver) {
track(target, prop)
return Reflect.get(...arguments)
},
set(target, key, value, receiver) {
trigger(target, key)
return Reflect.set(...arguments)
}
}

const proxy = new Proxy(dinner, handler)
console.log(proxy.meal)

在Propxy的拦截操作中,可以做任何想做的事情,通过是利用Reflect方法,可以完成拦截前的原始行为,并且可以正确的执行this绑定

  • 检测:Vue3不在需要检测数据变化,而是用Proxy拦截
  • 跟踪更改数据的函数:在Proxy的Getter中执行操作,称为effect
  • 触发函数来更新数据:在Proxy的Setter中执行操作,称为trigger

Proxy对象

Vue始终返回一个对象的Proxy版本,在响应式Proxy对象访问嵌套对象时,返回的对象也是Proxy对象:

1
2
3
4
5
6
7
8
9
10
11
12
const handler = {
get(target, prop, receiver) {
track(target, prop)
const value = Reflect.get(...arguments)
if (isObject(value)) {
return reactive(value)
} else {
return value
}
}
// ...
}

Proxy vs 原始对象

经过Proxy代理的对象,与原始对象使用===进行比较时,会返回false,所以在例如filter等方法中要注意。

使用选项式API时一般不会出现这种浸膏,因为所有响应式数据都是通过this访问的,全部为代理后的对象

但是使用组合式API时,有可能会遇到这个问题,最近做法是不要保留对原始对象的引用,只使用响应式版本

侦听器

每个组件都有一个相应的侦听器实例,该实例将在组件渲染期间把所有访问的Property记录为依赖项,发过来,组件的侦听器就成为了每个Property的订阅者。之后,当触发依赖项的Setter时,它会通知其所有订阅的侦听器,从而使组件重新渲染