这次来介绍reactive与shallowReactive的区别,也就是深响应和浅响应的区别
首先我们现在实现的reactive是浅响应的,就拿下面代码来说:
const obj = reactive{
foo: {bar:1}
}
effect(()=>{
console.log(obj.foo.bar)
})
//修改obj.foo.bar的值,并不能触发响应
obj.foo.bar = 2
为什么修改obj.foo.bar不能触发副作用函数重新执行。来看下现在的实现:
function reactive(obj){
return new Proxy(obj, {
get(target, key, receiver){
if(key === 'raw'){
return target
}
track(target, key)
// 当读取属性值时,直接返回结果
return Reflect.get(target, key, receiver)
}
})
}
看上面的代码,要读取obj.foo.bar,首先要读取obj.foo的值。由于通过Reflect.get得到obj.foo的结果是一个普通对象,并不是一个响应式对象,所以在副作用函数中访问时不能建立响应联系。要解决这个问题,就要对Reflect.get返回的结果做一层包装:
function reactive(obj){
return new Proxy(obj, {
get(target, key, receiver){
if(key === 'raw'){
return target
}
track(target, key)
const res = Reflect.get(target, key, receiver)
if(typeof res === 'object' && res !== null){
// 调用reactive将结果包装成响应式数据并返回
return reactive(res)
}
return res
}
})
}
当Reflect返回的值是对象,则递归地调用reactive函数并将其包装称响应式数据并返回。这样通过obj.foo.bar读取bar属性值时,自然就会建立响应联系,这样修改值时,就能够触发副作用函数重新执行。
但是不是所有情况下都要是深响应的,这就催生了shallowReactive,即浅响应,指的是只有对象的第一层属性是响应的。例如:
const obj = shallowReactive({foo:{bar:1}})
effect(()=>{
console.log(obj.foo.bar)
})
// obj.foo是响应的,可以触发副作用函数重新执行
obj.foo = {bar:2}
// obj.foo.bar不是响应的,不能触发副作用函数重新执行
obj.foo.bar = 3
在这例子,我们使用shallowReactive函数创建一个浅响应的代理对象obj。要实现此功能,看下面代码:
// 封装createReactive函数,接收一个参数isShallow,代表是否为浅响应,默认为false
function createReactive(obj, isShallow = false){
return new Proxy(obj, {
get(target, key, receiver){
if(key === 'raw'){
return target
}
track(traget, key)
const res = Reflect.get(target, key, receiver)
//如果是浅响应,则直接返回原始值
if(isShallow){
return res
}
if(typeof res === 'object' && res !== null){
return reactive(res)
}
return res
}
})
}
这样就实现了reactive以及shallowReactive函数
function reactive(obj){
return createReactive(obj)
}
function shallowReactive(obj){
return createReactive(obj, true)
}