reactive
是vue响应式的核心
reactive
一般和 effect
结合使用
const { reactive, effect } = VueReactivity
const state = reactive({ name: 'kortin', age: 23 })
effect(() => {
el.innerHTML = state.name + '今年' + state.age + '岁了'
})
setTimeout(() => {
state.age ++
}, 3000)
上面例子中,
reactive
将数据变成响应式,是用 ES6 中新的API Proxy
实现的
effect
是副作用函数,如果此函数中依赖的数据发生变化,会重新执行
副作用函数会默认执行一次,对依赖的响应式数据取值
1) 简单的 Proxy
代理对象
export function reactive<T extends object>(target: T) {
if (!isObject(target)) return;
return new Proxy(target, {
// 取值时会调用get
get(target, key, receiver) {
return target[key]
},
// 赋值时会调用set
set(target, key, value, receiver) {
target[key] = value
return true
}
})
}
2) Reflect
解决 this
指向问题
let person = {
firstName: '周',
lastName: '昊天',
get name() {
return this.firstName + this.lastName
}
}
如果访问了 name
(对象属性访问器),而 name
依赖访问了 firstName
和 lastName
。
这种情况下, firstName
和 lastName
的依赖都应该被收集。
为了解决上面的问题,需要引入 Reflect
export function reactive<T extends object>(target: T) {
if (!isObject(target)) return;
return new Proxy(target, {
get(target, key, receiver) {
return Reflect.get(target, key, receiver)
},
set(target, key, value, receiver) {
return Reflect.set(target, key, value, receiver)
}
}
receiver
就是当前的 Proxy
对象,通过 Reflect
在读取 target
属性时将 this
指向到当前的 Proxy
对象上。
3) 同一个 target
重复声明响应式
如果同一个 target
对象进行了两次响应式声明后 new
了两个 Proxy
对象,显然两个 Proxy
对象是不相等的,实际上,同一个对象的响应式对象应该也是相同的。