Vue 3中Object.assign与响应式数据?

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

前端小白,在学习Vue 3 响应式数据的时候,遇到了一个问题

<script lang="ts">
  export default{
    name:"test",
  }
</script>
<script lang="ts" setup>
  import {toRefs,ref,reactive} from "vue";

  let person = reactive({aa:"abc",bb:123})

  function c(){
    console.log(1)
    console.log(person)

    Object.assign(person,{aa:"121231",bb:12131})

    person =  {aa:"hhh",bb:13}   
    person =  {aa:"hh",bb:132} 
    
    console.log(person)
  }
  
</script>
<template>
  <span>姓名:{{person.aa}} </span> <br>

  <button @click="c">点击修改数据</button>

</template>

vue3官方文档中有如下说明Vue 3中Object.assign与响应式数据?

对于上面的代码和文档描述,按理说结果是姓名:121231,但是实际运行结果是姓名:hh

如果Object.assign(person,{aa:"121231",bb:12131})不存在,或者说不是先执行,确实是无法在页面上修改数据为hh,但是只要这一行代码存在并且先执行,就会修改为hh

根据上述现象,初步判断可能是Object.assign(person,{aa:"121231",bb:12131})代码副作用,查了MDN,说该API会调用get/set方法。

Vue 3中Object.assign与响应式数据?

虽然vue是通过监听set/get方法实现的响应式渲染,上述mdn内容只是说明了Object.assign(person,{aa:"121231",bb:12131})为什么有效,但是还是不能解决我的疑惑

希望大佬说一下原因

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

造成这个现象的原因是 Object.assign 修改了 person 的属性,触发了组件更新,从编译完成后的代码我们可以看出,template 最终被编译成了 render function,其中引用了 person.aa,也就是说 render function 会被收集为 person.aa 的依赖

Object.assign(person,{aa:"121231",bb:12131}) 被执行,也就意味着 render function 会被重新执行,但这里很重要的一点是,vue的更新是异步的,状态变化驱动的更新会被合并到下一个 nextTick 执行

综上,这里的执行顺序其实是

  1. Object.assign(person,{aa:"121231",bb:12131})
  2. person = {aa:"hhh",bb:13}
  3. person = {aa:"hh",bb:132}
  4. ...
  5. render function answer image

这就是为什么步骤3中 person = {aa:"hh",bb:132} 能影响渲染结果,但重新赋值也导致其丢掉了响应性

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