模拟实现Vue.js 3.0中创建响应式对象的函数ref和toRefs,以及computed

函数ref和toRefs,以及computed

模拟实现ref函数

  • ref的使用
    • 它接收一个参数,可以是原始类型值也可以是对象,
    • 如果传入的是对象,并且这个对象是ref创建的对象,那直接返回。
    • 如果是普通对象的话,它内部会调用reactive来创建响应式对象
    • 否则对的话创建一个只有value属性响应式对象
    • 返回创建的响应式对象
  • ref函数的定义
    • 代码如下:
    function convert(target) {
      return isObject(target) ? reactive(target) : target;
    }
    export function ref(raw) {
      // 判断raw 是否是由ref创建的响应式对象,如果是对的话直接返回
      if (isObject(raw) && raw.__v_isRef) {
        return raw;
      }
      let value = convert(raw);
      const r = {
        __v_isRef: true,
        get value() {
          track(r, 'value');
          return value;
        },
        set value(newValue) {
          if (newValue !== value) {
            raw = newValue;
            value = convert(raw);
            trigger(r, 'value');
          }
        },
      };
      return r;
    }
    

refreactive的区别

  • ref 可以把基本类型的数据,转换成响应式对象,当获取数据时要使用value属性,模版中使用的时候可以省略value。而 reactive不能把基本类型的数据转换成响应式对象。
  • ref返回的对象,重新给value属性赋值成对象以后也是响应式的。代码中是通过convert逻辑来处理的。
  • reactive 返回的对象,重新赋值以后会丢失响应式,因为重新赋值的对象不再是代理对象。
  • reactive 返回的对象不可以解构,如果想要解构的话,需要使用toRefs函数来处理reactive返回的对象。
  • 如果一个对象中的成员比较多的时候,使用ref并不方便,因为要取值总要带着value属性。如果一个函数内部只有一个响应式数据,这个时候使用ref会比较方便。因为可以直接解构返回。在这里插入图片描述

模拟实现toRefs函数

  • toRefs的作用

    • 它接收一个reactive返回的响应式对象proxy,也就是Proxy对象。如果传入的的参数不是reactive创建的响应式对象,直接返回。
    • 把传入对象的所有属性转换成一个类似于ref返回的对象,根据proxy的类型创建一个新的同类型的对象作为函数返回值,把转换后的属性挂载到一个新的对象上并将其返回。
  • toRefs的实现

    • toRefs的执行逻辑
    Created with Raphaël 2.3.0开始传入一个参数 proxyproxy 是否是一个 reactive函数创建的对象?proxy 是数组?let ret = new Array(proxy.length)遍历proxy的每一个属性,把每一个属性都转换成ref返回的对象,并挂载到ret上,即ret[propertyKey] = toProxyRef(propertyKey)返回 ret结束let ret = {}发送警告(参数必须是一个由reactive创建的Proxy对象)yesnoyesno
    • toRefs的函数定义:
export function toRefs(proxy) {
  // 判断proxy是否是reactive创建的对象。这里因为我们的的reactive没有添加标记,暂时忽略此步骤
  // 根据proxy是否为数组类型,创建一个返回对象
  const ret = proxy instanceof Array ? new Array(proxy.length) : {};

  // 遍历proxy的每一给属性,将其转换成ref返回的对象,并一一挂载到新对象ret上
  for (const key in proxy) {
    ret[key] = toProxyRef(proxy, key);
  }
  return ret;
}

function toProxyRef(proxy, key) {
  const r = {
    __v_isRef: true,
    get value() {
      return proxy[key];
    },
    set value(newValue) {
      proxy[key] = newValue;
    },
  };
  return r;
}

【在线演示案例地址】

模拟实现computed函数

  • computed的作用

    • computed接收一个有返回值的函数作为参数getter,这个函数的返回值就是计算属性的值。并且我们要监听这个函数内部使用的响应式数据的变化,最后把这个函数执行的结果返回。
    • computed函数内部会通过effect监听getter内部的响应式数据的变化。因为在effect中,执行getter的时候访问响应式数据的属性,会去收集依赖。
    • 当数据变化后会重新之心effect函数。把getter的结果再存储到result中。
  • computed函数的定义

    export function computed(getter) {
      const result = ref();
      effect(() => (result.value = getter()));
      return result;
    }
    

【在线演示案例地址】

至此,Vue.js 3.0的响应式原理就已经介绍完了。


版权声明:本文为u011024243原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。