接下来是响应式的下半场,ref,toRefs, computed,废话不多说进入学习!
ref
分析:
这也是创建响应式对象的函数, 他接收一个参数,可以是原始值也可以是对象,如果是通过ref创建的响应式对象就直接返回,如果是一个普通的对象,内部会调用reactive函数,将基于普通对象创建一个响应式对象。否则会创建一个具有value的响应式对象,并返回。接下来我们来实现它!
代码实现:
export function ref (raw) {
// 判断raw 是否是ref创建的对象,如果是直接返回
if(isObject(raw) && raw.__v_isRef) {
return raw
}
// 如果是一个普通对象则convert那里调用reactive,如果是原始类型值直接返回
let value = convert(raw);
// 创建一个对象,并添加一个value属性成员,添加get set来做依赖收集和触发更新,生成响应式对象。并做标记是通过ref生成的。
const result = {
__v_isRef: true,
get value () {
track(result, 'value')
return value
},
set value (newValue) {
if(newValue !== value) {
raw = newValue
value = convert(raw);
trigger(result, 'value')
}
}
}
return result
}
复制代码
reactive VS ref
- ref 可以把基本数据类型数据,转化成响应式对象
我们可以在代码中可以看到,会将基本数据类型转化成一个有value属性的对象,再将这个对象转化成响应式对象 - ref 返回的对象,重新赋值成对象也是响应式的
因为该对象是在ref里面生成的,对象不会变,只是value的属性值发生变化而已 - reactive 返回的对象,重新赋值丢失响应式
从第四天的reactive代码中也可以看得出来重新赋值的话就不是proxy代理对象了而是一个普通对象失去响应式 - reactive 返回的对象不可以结构
结构出来以后,就不属于这个代理对象的属性,而是一个普通的变量,脱离代理对象,失去get set deleteProperty,失去响应式。
我们自己实现了响应式之后,就很容易明白这些问题,直接在实战场景中学习,会更了解问题的本质。
- 如果一个对象属性多的时候可以使用reactive,如果一个对象属性少的话最好使用ref,因为这样生成的响应式对象可以结构返回。
toRefs
分析:
- 这个函数接收一个reactive对象,也就是Proxy对象。如果这个对象不是reactive创建的对象则直接返回。
- 然后把对象的所有属性转换成一个类似ref返回的对象,把转化后的属性挂载到一个新的对象返回
代码实现:
export function toRefs (proxy) {
const ret = proxy instanceof Array ? new Array(proxy.length) : {}
for(const key in proxy) {
ret[key] = toProxyRef(proxy, key)// 返回类似的ref对象,没有进行依赖收集
}
return ret
}
function toProxyRef (proxy, key) {
const r = {
__v_isRef: true,
get value () {
// 这里不需要去收集依赖,因为这里会有自身的proxy里面去收集
return proxy[key] // 当这样访问proxy对象的key属性时就会触发proxy对象依赖收集
},
set value(newValue) {
proxy[key] = newValue // 这设置值的时候也会触发proxy key的更新
}
}
return r
}
复制代码
computed
computed需要就收一个有返回值的函数作为参数,这个函数的返回值就是计算属性的值,并且要监听这个函数里面响应式数据的变化,最后把这个函数执行结果返回。
export function computed (getter) {
const result = ref();
effect(() => (result.value = getter()))
return result
}
// 使用
let total = computed(() => {
return price.value * count.value
})
console.log(total.value)
复制代码
总结
到这里,我们模拟了vue3 响应式系统中的reactive,ref, toRefs, computed的内部实现,还实现了依赖收集,和触发更新的track, trigger, effect 比较底层的函数,一般情况下我们不会去调用。希望这两篇文章对vue3响应式原理有个大概的了解,欢迎评论区讨论,下面会贴上代码!
[模式实现源码](github.com/zelixag/vue…
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END