如存在三元运算符时,怎么处理
// 原始数据
const data = { text: 'hello world',ok:true}
// 副作用函数存在三元运算符
effect(function effectFn(){
document.body.innerText = obj.ok ? obj.text : 'not'
})
// 理解如此,obj.ok和obj.text都会绑定effectFn函数,所以不管obj.ok 是true还是false ,obj.text值改变都会执行effectFn副作用函数,然而当obj.ok为false时,obj.text值无论怎么改变,都不应该执行effectFn副作用函数。
解决方案:每次执行副作用 函数,可以先把它从所有与之关联的依赖集合中删除。当副作用函数执行完后,会重新建立关系。
// 用一个全局变量储存被注册的副作用函数
let activeEffect
// effect 函数用于注册副作用函数
function effect(fn){
// 当 effectFn 执行时,将其设置为当前激活的副作用函数
const effectFn = ()=>{
// 调用cleanup完成清除工作
cleanup(effectFn)
// 当调用effect注册副作用函数时,将副作用函数fn赋值给activeEffect
activeEffect = effectFn
// 执行副作用函数
fn()
}
// activeEffect.deps 用来存储所有与被副作用函数相关的依赖集合
effectFn.deps = []
// 执行副作用函数
effectFn()
}
// 清除工作
function cleanup(effectFn){
// 遍历`effectFn.deps 数组
for(let i=0; i< effectFn.deps.length; i++){
// deps 是依赖集合
const deps = effectFn.deps[i]
// 将 effectFn 从依赖集合中移除
deps.delete(effectFn)
}
// 最后需要重置 effectFn.deeps 数组
effectFn.deps.length = 0
}
// 储存副作用函数的桶
const bucket = new WeakMap()
// 原始数据
const data = { text: 'hello world',ok:true}
// 对原始数据的代理
const obj = new Proxy(data,{
// 拦截读取操作
get(target,key){
track(target,key)
// 返回属性值
return target[key]
},
// 拦截设置操作
set(target,key,newValue){
console.log('bucket:',bucket)
// 设置属性值
target[key] = newValue
trigger(target,key)
return true
}
})
// 在 get 拦截函数内调用 track 函数追踪变化
function track(target,key){
// 没有 activeEffect 直接 return
if(!activeEffect) return target[key]
// 根据 target 从 “桶” 中 取得 depsMap,它也是一个map 类型 key --》effects
let depsMap = bucket.get(target)
// 如果不存在 depsMap 那么新建一个Map 并与 target 关联
if(!depsMap){
bucket.set(target,(depsMap = new Map()))
}
// 再根据 key 从 depsMap 中取得 deps,它是一个 set 类型
// 里面储存着所有与当前key 相关联的副作用函数,effects
let deps = depsMap.get(key)
// 如果 deps 不存在 同样新建一个set 并与 key 关联
if(!deps){
depsMap.set(key,(deps = new Set()))
}
// 最后将当前激活的副作用函数添加到“桶”
deps.add(activeEffect)
// deps 就是一个与当前副作用函数存在关联的依赖集合
// 将其添加到activeEffect.deps 数组中
activeEffect.deps.push(deps) // 新增
}
// 在 set 拦截函数内调用 trigger 函数 触发变化
function trigger(target,key){
// 根据 target 从桶中取得 depsMap,它是key --》effects
const depsMap = bucket.get(target)
if(!depsMap) return true
// 根据 key 取得所有副作用函数 effects
const effects = depsMap.get(key)
// new Set 是为了防止 effectFn 执行时,进行无限的循环
const effectsToRun = new Set(effects)
effectsToRun.forEach(effectFn => effectFn())
// 执行副作用函数
// effects && effects.forEach(fn => fn())
}
// 执行副作用函数,触发读取
effect(function effectFn(){
document.body.innerText = obj.ok ? obj.text : 'not'
})
// 1 秒后修改响应式数据
setTimeout(()=>{
obj.text = 'hello vue3'
},1000)
setTimeout(()=>{
obj.ok = false
},3000)
本文含有隐藏内容,请 开通VIP 后查看