shallowReactive与reactive的原理浅析
vue3中的shallowReactive与reactive是怎么实现的呢?学习自尚硅谷
目的
使一个正常的object对象转化为响应式对象
解决方案
简单的说,就是w3c在object的增删改查时增加了hook函数,可以让用户对原生js获取事件、赋值事件等进行捕捉。这个hook函数就是Proxy与Reflect.
我接下来做的一件事就是使用这个hook函数,来使一个正常的object对象转化为响应式对象。
严格来讲,这个最后结果还不是响应式对象,只是这个object再增删改查属性的时候会触发自定义逻辑,具体编写什么样的逻辑能能够做到vue3中的响应式,本文没有阐述。
可以首先定义一个事件处理函数,对原生js获取事件、赋值事件等进行捕捉,随后再传递给Reflect
const reactiveHandler = {
get (target, key) {
if (key==='_is_reactive') return true
console.log('数据已获取');
return Reflect.get(target, key)
},
set (target, key, value) {
const result = Reflect.set(target, key, value)
console.log('数据已更新, 去更新界面')
return result
},
deleteProperty (target, key) {
const result = Reflect.deleteProperty(target, key)
console.log('数据已删除, 去更新界面')
return result
},
}
然后就可以进行转化了:
/*
自定义shallowReactive
目的是让该对象成为一个Proxy对象,方便对一些增删改查的方法进行拦截并添加自定义逻辑
*/
function shallowReactive(obj) {
return new Proxy(obj, reactiveHandler)
}
/*
自定义reactive
目的是让该对象,以及该对象内部所有object类型的成员成为一个Proxy对象,方便对一些增删改查的方法进行拦截并添加自定义逻辑
*/
function reactive (target) {
if (target && typeof target==='object') {
// 内部代码块的作用是:
// 1. 遍历子元素,目的是查看子元素中是否存在object,如果存在再次进入子元素;
// 2. 最终返回一个代理对象Proxy,代理该object
if (target instanceof Array) {
// 检测到是数组
target.forEach((item, index) => {
target[index] = reactive(item)
})
} else {
// 检测到是对象
Object.keys(target).forEach(key => {
target[key] = reactive(target[key])
})
}
// 如果这个taraget是一个object,下面的代码是无论如何都会对这个object执行的
// 换句话说:对每一个子object类型的对象,执行了下面的代码
const proxy = new Proxy(target, reactiveHandler)
return proxy
}
// 如果不是object,则直接返回
return target
}
console.log('=================测试自定义shallowReactive');
const proxy = shallowReactive({
a: {
b: 3
}
})
proxy.a = {b: 4} // 劫持到了
proxy.a.b = 5 // 没有劫持到
console.log('=================测试自定义reactive');
/* 测试自定义reactive */
const obj = {
a: 'abc',
b: [{x: 1}],
c: {x: [11]},
}
const proxy2 = reactive(obj)
console.log(proxy2)
proxy2.b[0].x += 1
proxy2.c.x[0] += 1