首页 > 其他分享 >vue3 修改原对象,赋值原对象的ref或者reactive如何产生响应式视图变更,vue失去响应式的原因

vue3 修改原对象,赋值原对象的ref或者reactive如何产生响应式视图变更,vue失去响应式的原因

时间:2024-10-20 22:43:16浏览次数:1  
标签:obj1 vue console log 视图 响应 ref 赋值

代码测试

<template>
  <div class='box'>
    {{ demo[0]?.a?.b?.c }}
  </div>
</template>
<script lang='ts' setup>
import { ref, reactive, computed, onMounted, nextTick, PropType, toRaw } from 'vue';
import { cloneDeep } from "lodash-es"

const obj1 = {
  a: {
    b: {
      c: 1
    }
  }
}

const arr1 = [obj1, { "a": 3 }, { "a": "slkdjfslkfdjs" }]

console.log(arr1[0] === obj1, "打印结果是true,说明用的是同一块内存引用")

const demo = ref<any>(arr1)

console.log(demo.value[0] === obj1, "打印结果是false,因为demo.value[0] 已经是一个proxy包装的对象了")

console.log(toRaw(demo.value[0]) === obj1, "打印结果是true,说明toRaw不是单纯的拷贝一份对象返回的,而是返回原对象的引用,所以和obj1是对等的")

setTimeout(() => {
  obj1.a.b.c = 7


  demo.value.map((i, index) => {
    console.log(toRaw(i), "原始值")
    console.log(obj1, "obj1")
    if (index === 0) {
      console.log(toRaw(i) === obj1, "slkvnskdjlsfsdfnlsfsjlkfj")
    }
    if (toRaw(i) === obj1) {
      console.log("find found")
      // 下面这样也不能触发响应式,因为i是个proxy对象,不能直接赋值,直接赋值会失去proxy,变成一个单纯的对象
      //i = obj1;

      //下面这样不能使视图发生改变,因为内存是一致的,数据没发生改变,不会触发页面响应式
      //i = Object.assign(i, obj1)

      //下面这样也可以使视图发生改变,因为深拷贝了一份内存数据,引用发生改变,所以赋值会使vue监听到且比较数据变更不同才会响应式刷新页面
      //demo.value[index] = cloneDeep(obj1)

      // 下面这样可以使 视图发生改变,i是proxy,需要通过Object.assign 等方式赋值,这样就能响应式,且还是那个proxy对象
      //i = Object.assign(i, cloneDeep(obj1))

      // 这样也能产生响应式,因为引用地址发生了变化,也就是数据发生了改变,b的引用内存地址发生了改变
      //i.a.b = cloneDeep(obj1.a.b)

      //下面这样还是不能响应式,因为i.a.b.c发生改变,obj1.a.b.c也同样变为null
      /* i.a.b.c = null;
      nextTick(() => {
        //所以这里赋值还是同样的值赋值同样的值,不会让vue发生视图变更,因为比较结果是一样
        i.a.b.c = obj1.a.b.c;
        console.log(i.a.b, "sldfjsldjfslk")
      }) */


      //下面这样就能发生数据不一致的比较变更,从而使视图发生改变
      //const copy = cloneDeep(obj1.a.b.c);
      const copy = obj1.a.b.c; //如果c是对象或者数组,就需要clone下了,要不然引用地址会一样
      i.a.b.c = null;
      nextTick(() => {
        //这样赋值不一样的数据,就能使视图发生更新,因为null和copy这个变量的数据值不一样
        i.a.b.c = copy;
        console.log(i.a.b, "sdfsvsdsfsdfsd")
      })
    }
  })

}, 2000)

</script>
<style lang='scss' scoped></style>

结论

  • vue能够视图产生变更的2个必要前提:
    1、必须通过ref或者reactive进行数据修改
    2、ref或者reactive是多层次的对象数据,修改子对象数据后的数据必须和修改前的数据不一致才能被vue识别产生变更。体现再要么内存引用发生变更,要么是基本数据类型的值发生变更,
  • 没发生响应式的情况
    1、修改了ref拷贝的原对象,虽然是同一份内存引用,但是不是通过ref进行修改的,所以不会发生视图变更,但是ref的内存数据确实也改变了。
    2、修改了的子对象是一个基本的数据类型,赋值了同样的值也不会发生数据改变,因为vue比较变更后发现没变更就不会执行之徒更新
  • 要想视图一定会发生发生更新,务必遵守
    1、通过ref或者reactive进行数据修改
    2、修改后的数据一定得和修改前的数据不一样,要么进行对象的引用变更,要么对基本数据类型的值进行变更才能响应式

标签:obj1,vue,console,log,视图,响应,ref,赋值
From: https://www.cnblogs.com/jocongmin/p/18488096

相关文章