vue3系列-响应式(二)

58 阅读1分钟

简述

上面一篇提到怎么才能把数据变成响应式的问题,这篇文章我们来实现

响应式数据的的简单实现

在vue2.X中对于响应式的原理是采用了defineProperty的方法,但是在vue3中是采用了proxy的方法,这里我们也会发现,当我们修改了obj.text的值的时候,会触发字段obj.text的设置操作。基于上面的思路来编写代码

// const obj = {text:'hello vue3!'}
const data = {text:'hello vue3!'}
const obj = new Proxy(data,{
set(target,key,newVal){
target[key] = newVal
effect()
}
})
effect()
function effect(params) {
document.body.innerText = obj.text
}
setTimeout(()=>{
obj.text = '我是修改后的数据'
// effect()
},1000)

上面的代码基本可以实现数据更新页面也更新的响应式,不过目前的实现还有很多缺陷,比如我们直接通过名字(effect)来获取副作用函数,这种硬编码的方式很不灵活。副作用函数的名字可以任意取,甚至可以是一个匿名函数,因此下面我们改掉这种硬编码的方式。


<script>
const data = {text:'hello vue3!'}
const bucket = new Set()
const obj = new Proxy(data,{
get(target,key){
//将副作用函数添加到副作用函数的桶里
if (activeEffect) {
bucket.add(activeEffect)
}
return target[key]
},

set(target,key,newVal){
target[key] = newVal
//把副作用函数从桶里面取出来并执行
bucket.forEach(fn=>fn())
return true
}
})

let activeEffect = null
function effect(fn){ //这里我们硬编码了副作用函数,导致一旦副作用函数的名字不叫effect的时候这段代码不能执行
// document.body.innerText = obj.text
console.log(fn)
activeEffect = fn
fn()
}

effect(()=>{
console.log('我是副作用函数!') //这里会打印两次
document.body.innerText = obj.text })
setTimeout(()=>{ //这里我们修改一个没有存在的节点
obj.noNode = '我是修改后的数据'
},1000)

</script>

如上面的代码,由于副作用函数放在了activeEffect中,这样响应式的系统就不依赖副作用函数的名字了,并且我们定义了一个Set,用来收集副作用函数。这里会出现一个问题就是当我们修改obj的其他属性的时候,也会调用当前的副作用的函数,这是因为我们没有把副作用的函数与当前节点关联起来。

怎么解决当前的这个问题,我们关注下一篇文章。