本文已参与「新人创作礼」活动,一起开启掘金创作之路。
上篇我们介绍了 vue设计与实现-调度器
调度器的实现对于我们实现computed有极大的作用,我们这次从使用computed的角度,反推一下computed的实现逻辑。
computed的使用
//我们一般这样使用
const count = ref(1)
const plusOne = computed(() => count.value + 1)
当然,还有第二种对象的方式,我们目前先讨论这种回调函数的方式
反推
我们在computed的回调函数中读取了一个响应式数据:count,然后当我们读取plusOne时,然后将count的值加1 return出去 赋值给到plusOne
结合track和trigger去思考:
读取plusOne时,要读取cout,收集count的依赖函数(这个时候,是会触发一遍effect函数的)
我们大胆的设想一下:如果effect是这样子的:
effect(()=>{
() => count.value + 1
})
1.那我们等于是要拿到effect函数执行的返回值,
2.然后将返回值给到用户所定义的属性上面
思路及实现
基于以上两点思考,我们逐一实现一下
实现获取effect函数返回值
我们的effect函数如下,这是未实现effect返回值的代码:
let effect=(fn,option={})=>{
//清空effectFn 的deps
const effectFn=()=>{
cleanUp(effectFn)
activeEffect=effectFn
effectStack.push(effectFn)
fn()
effectStack.pop()
activeEffect=effectStack[effectStack.length-1]
}
effectFn.deps=[]
effectFn.option=option
effectFn()
}
我们可以看到,我们第一次读取的时候,执行fn()函数,fn就是 () => count.value + 1 也就是我们要拿到fn的返回值,并且返回出去给到用户使用
修改后的代码如下:
let effect=(fn,option={})=>{
const effectFn=()=>{
cleanUp(effectFn)
activeEffect=effectFn
effectStack.push(effectFn)
const res=fn()//这里我们定义了res接收返回值
effectStack.pop()
activeEffect=effectStack[effectStack.length-1]
return res //将res返回出去给用户使用
}
effectFn.deps=[]
effectFn.option=option
if(option.lazy){
return effectFn
}else{
effectFn()
}
}
实现computed
基于computed 的使用(回调函数的使用),我们可以粗糙的实现一下
function computed(fn){
const res= effect(fn)
return res
}
大概是这个鬼样子...
const result= computed(()=>{
return count.value + 1
})
console.log(result)
我们只需要将要触发的函数传入进入就可以啦
然后执行代码
为什么获取不到?
一个小bug
注意:我们在computed函数里面返回的是什么?是effect的返回值!
但是我们需要的effect内部effectFn()的返回值,这可咋办?难道我们在effect内部定义一个变量接收effectFn()的返回值,然后返回出去?这样实现的方式不利于管理
不对!我们上篇实现了什么?调度器, 是一个对象包裹着schedule,我们可以在option里面传入一个状态值,去控制effectFn是否返回,是否懒加载
实现effect返回一个effectFn
调用effect
effect(()=>{},{
lazy:true//懒加载effectFn
})
effect函数修改如下:
let effect=(fn,option={})=>{
//清空effectFn 的deps
const effectFn=()=>{
cleanUp(effectFn)
activeEffect=effectFn
effectStack.push(effectFn)
const res=fn()
effectStack.pop()
activeEffect=effectStack[effectStack.length-1]
return res
}
effectFn.deps=[]
effectFn.option=option
if(option.lazy){
//懒加载effectFn
return effectFn
}else{
effectFn()
}
}
通过lazy的值,去控制执行effectFn 还是缓存effectFn,交给用户来选择
这样我们的computed也要做一些修改
修改computed
function computed(fn){
const effectFn= effect(fn,{
lazy:true
})
return effectFn()
}
执行computed
const result= computed(()=>{
return count.value + 1
})
console.log(result)
这样我们就能获取到effectFn的返回值了
以上,我们便简单的实现了computed 功能,目前实现的功能存在着一些问题,不知道各位小伙伴看出来了没有?
欢迎小伙伴在评论区留言哈~ 😊