• vue3解构响应式失效解析


    vue3解构响应式失效解析

    在使用vue3时,我们发现不能使用解构来处理响应式数据,今天我们来看看究竟是为什么。

    vue3中解构响应式数据

    <div>{{counter}}</div>
    <div>{{obj.value}}</div>
    
    
    const reactiveObj = reactive({
      counter: 0,
      obj: {
        value: 1
      }
    });
    setInterval(() => {
      reactiveObj.counter++;
      reactiveObj.obj.value++;
    }, 1000);
    const { counter, obj } = reactiveObj;
    return {
      counter,
      obj
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在页面上可以看到,counter的值不会变,obj.a的值倒是一直在递增。

    我们都知道vue3是使用ES6proxy特性来实现响应式的,先来回顾一下proxy

    const obj = {
        value: 1
    }
    
    const proxy = new Proxy(obj, {
        get: function(target, key) {
            return Reflect.get(...arguments);
        },
        set: function(target, key, value) {
            return Reflect.set(...arguments)
        }
    })
    
    proxy.value++;
    console.log(proxy.value);   // 2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    proxy本身就是对对象进行拦截,通过new Proxy的返回值,拦截obj对象,当操作对象中的值时,会触发set或者get

    但是对于原始值(stringnumber这些),就需要在外部包裹一下变成一个对象,不然没办法使用new Proxy去拦截。

    我们来看看vue3是如何处理的。

    vue3中,使用ref来为基本数据类型添加响应式。

    export function ref(value?: unknown) {
      return createRef(value, false)
    }
    
    function createRef(rawValue: unknown, shallow: boolean) {
      if (isRef(rawValue)) {
        return rawValue
      }
      // 使用一个对象包裹基本数据类型数据
      return new RefImpl(rawValue, shallow)
    }
    
    class RefImpl<T> {
      private _value: T
      private _rawValue: T
    
      public dep?: Dep = undefined
      public readonly __v_isRef = true
    
      constructor(value: T, public readonly __v_isShallow: boolean) {
        this._rawValue = __v_isShallow ? value : toRaw(value)
        this._value = __v_isShallow ? value : toReactive(value)
      }
    
      get value() {
        trackRefValue(this)
        return this._value
      }
    
      set value(newVal) {
        newVal = this.__v_isShallow ? newVal : toRaw(newVal)
        if (hasChanged(newVal, this._rawValue)) {
          this._rawValue = newVal
          this._value = this.__v_isShallow ? newVal : toReactive(newVal)
          triggerRefValue(this, newVal)
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    从上面的代码可以发现,vue3把原始值包装成一个对象,通过get valueset value方法来对原始值进行访问,这样在访问值的时候就必须携带.value了。

    而对于对象而言,使用ref的话内部还是调用reactive

    export const toReactive = <T extends unknown>(value: T): T =>
      isObject(value) ? reactive(value) : value
    
    export function reactive(target: object) {
      if (isReadonly(target)) {
        return target
      }
      return createReactiveObject(
        target,
        false,
        mutableHandlers,
        mutableCollectionHandlers,
        reactiveMap
      )
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    但是还是需要通过.value去访问内部的响应式数据.

    let reactiveObj = ref({
      counter: 0,
      obj: {
        a: 1
      }
    });
    console.log(reactiveObj.value.obj.a);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    为什么解构会破坏响应式?

    解构赋值,区分基本数据类型和引用类型的赋值,原始类型的赋值相当于按值传递,引用类型的值就相当于按引用传递。

    const obj = {
      value: 1obj1: {
        value: 1
      }
    }
    const val = obj.value;
    const obj1 = obj.obj1;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    上方的val虽然是obj.value的值,但是当访问val时,已经绕过了obj对象的get方法,也就是本文讨论的失去响应式。

    obj1在解构出来的值是按引用传递的,内部的指针依然指向obj.obj1,所以去访问其中的内容并不会失去响应式。

  • 相关阅读:
    深度强化学习之gym扫地机器人环境的搭建(持续更新算法,附源码,python实现)
    docker-compose Wordpress遇到的很多问题
    十年老Python程序员:给我一个链接,没有我不能爬的视频,只有我顶不住的视频
    MATLAB算法实战应用案例精讲-【智能优化算法】算术优化算法-AOA(附matlab代码)
    【Ubuntu18.04】激光雷达与相机联合标定(Livox+HIKROBOT)(一)相机内参标定
    数据结构(一)线性表(模板实现)
    传奇外网架设教程
    springboot基于Java的果蔬产品销售系统毕业设计-附源码131110
    数据分析是什么?
    14:00面试,14:06就出来了,问的问题有点变态。。。
  • 原文地址:https://blog.csdn.net/qq_42880714/article/details/126374808