Vue3 之 reactive、ref、toRef、toRefs 使用与区别,源码分析详细注释

目录
  • reactive、ref、toRef、toRefs 使用与区别
    • reactive
    • ref 作用及用法
    • toRef 作用及用法
    • toRefs 作用及用法
  • ref,toRef,toRefs 源码实现解析详细注释

reactive、ref、toRef、toRefs 使用与区别

reactive

  • 参数传入普通对象,不论层级多深都可以返回响应式对象,(参数只能是对象)
  • 但是解构、扩展运算符会失去响应式

ref 作用及用法

  • 参数可以为任意类型,推荐使用基本类型
  • 使用时 需要通过 xxx.value 的形式获取
  • 本质是拷贝粘贴一份数据,脱离了与源数据的交互
  • 将对象中属性变成响应式数据,修改该数据是不会影响到源数据,但是会更新视图


toRef 作用及用法

  • 针对 reactive 解构失去响应式的问题,创建了 toRef,用于为源响应式对象上的属性新建一个 ref,保持对源对象属性的响应式交互。
  • 语法:toRef(target, key)
  • 使用时 需要通过 xxx.value 的形式获取
  • 本质是引用,与源数据有交互,修改该数据是会影响源数据,但是不会更新视图,如果需要更新视图,需要使用 reactive 包裹源数据


toRefs 作用及用法

  • 就是批量的 toRef 操作,toRefs 是一次性将 reactive 中的所有属性都转为 ref
  • 语法:toRefs(target)
  • 同样可以用于解构 reactive 的响应式对象
  • 使用时 需要通过 xxx.value 的形式获取
  • 本质是引用,与源数据有交互,修改该数据是会影响源数据,但是不会更新视图,如果需要更新视图,需要使用 reactive 包裹源数据


ref,toRef,toRefs 源码实现解析详细注释

ref 和 reactive 的底层原理区别: reactive 内部采用 proxy ,而 ref 中内部采用的是 defineProperty

ref、shallowRef 源码实现。使用class RefImpl实现,会被 babel 编译成defineProperty
其中 share.ts 和 reactive.ts 文件中的方法,不在赘述,详见上一篇 响应式原理的文章

import { hasChanged, isArray, isObject } from "./shared";
import { TrackOpTypes, TriggerOrTypes } from "./shared";
import { track, trigger } from "./effect";
import { reactive } from "./reactive";

export function ref(value) {
  return createRef(value);
}

//  shallowRef 只能处理基本类型数据
export function shallowRef(value) {
  return createRef(value, true);
}

const convert = (val) => (isObject(val) ? reactive(val) : val);
class RefImpl {
  public _value;
  public __v_isRef = true; // 实例添加 __v_isRef, 表示是一个ref属性
  constructor(public rawValue, public shallow) {
    // 1.参数前面加修饰符 表示实例属性
    this._value = shallow ? rawValue : convert(rawValue); // 如果是深度监听 需要把里面的都变成响应式的
  }
  // 2. 类的属性访问器
  get value() {
    // 3. 依赖收集 代理取值取_value
    track(this, TrackOpTypes.GET, "value"); // 依赖收集
    return this._value;
  }
  set value(newValue) {
    // 4. 判断老值和新值是否有变化
    if (hasChanged(newValue, this.rawValue)) {
      this.rawValue = newValue; // 新值会作为老值
      this._value = this.shallow ? newValue : convert(newValue);
      // 5. 触发更新
      trigger(this, TriggerOrTypes.SET, "value", newValue);
    }
  }
}
function createRef(rawValue, shallow = false) {
  return new RefImpl(rawValue, shallow);
}

toRef,toRefs 源码实现。使用class ObjectRefImpl实现,会被 babel 编译成defineProperty

class ObjectRefImpl {
  public __v_isRef = true; // 实例添加 __v_isRef, 表示是一个ref属性
  constructor(public target, public key) {}
  get value() {
    return this.target[this.key]; // 如果原对象是响应式的就会依赖收集
  }
  set value(newValue) {
    this.target[this.key] = newValue; // 如果原来对象是响应式的 那么就会触发更新
  }
}

// 将对象的某一个值转化成 ref类型
export function toRef(target, key) {
  return new ObjectRefImpl(target, key);
}

//  可能传递的是一个数组 或者对象,属性全部转化成 ref类型
export function toRefs(object) {
  const ret = isArray(object) ? new Array(object.length) : {};
  for (let key in object) {
    ret[key] = toRef(object, key); // 遍历调用toRef方法
  }
  return ret;
}

你可能感兴趣的:(Vue3,javascript,开发语言,ecmascript,前端)