为什么在Vue3响应式源码中,使用Reflect.set时先赋值再返回能够解决更新问题?

作者站长头像
站长
· 阅读数 26

关于自学vue3响应式源码-proxy中的一个问题(Reflect.set)

最近在看vue3响应式源码,自己手写时发现了一个情况是

export const reactive = (target) => {
    return new Proxy(target, {
        get(target, prop, recevier) {
            //依赖收集
            track(target, prop);
            return Reflect.get(...arguments);
        },
        set(target, prop, value, recevier) {
            let res = Reflect.set(...arguments);
            //触发依赖更新
            trigger(target, prop);
            //这里如果直接return Reflect.set(...arguments),则会有更新问题
            //比如在setTimeout中同时更新一个对象的两个属性,则计时器结束之后只会更新第一个属性,第二个不触发更新
            //先赋值res,再返回,则正常
            return res; 
        },

    })
}
   let animal = reactive(
        {
            name: 'dog',
            age: 2
        }
    )
    effect(() => {
        document.querySelector('#app').innerHTML = `
        <div>
            <h2>name: ${animal.name}</h2>
            <h2>age: ${animal.age}</h2>
        </div>
        `
    })

    setTimeout(()=>{
        animal.name = 'cat'//更新
        animal.age = 3//直接return Reflect.set不会更新
    },2000)

改为let res = Reflect.set(...arguments);再返回则正常

回复
1个回答
avatar
test
2024-06-18

animal.name = 'cat' 首次 trigger 时,animal 对象还未更新,拿到的是 {name: 'dog', age: 2}, 执行完 effect 后,使用 Reflect.set(...arguments) 进行设置,变为了 {name: 'cat', age: 2}

animal.age = 3 再次 trigger 时,拿到的 animal 值为 {name: 'cat', age: 2},表现为“第二个不触发更新”,最后使用不触发更新的 Reflect.set(...arguments) 进行设置,变为了 {name: 'cat', age: 3},页面无变化

回复
likes
适合作为回答的
  • 经过验证的有效解决办法
  • 自己的经验指引,对解决问题有帮助
  • 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
  • 询问内容细节或回复楼层
  • 与题目无关的内容
  • “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容