Vue.js 源码解析:深入 Vue 3 中 ref 和 reactive

前言:家人们,大家好!今天分享一篇文章给大家!要是文章对你有帮助,激发了你的灵感,

求个收藏 + 关注啦~后续还有超多惊喜,别错过!

目录

一、引言

二、ref 的源码解析

2.1 基本使用回顾

2.2 源码实现

源码解释

三、reactive 的源码解析

3.1 基本使用回顾

3.2 源码实现

源码解释

四、ref 和 reactive 的区别与联系

4.1 区别

4.2 联系

五、总结


一、引言

在 Vue 3 里,ref 和 reactive 是构建响应式系统的关键部分。它们为开发者提供了便捷的途径来创建响应式数据,使得数据变化时能自动更新 DOM。本文会深入探究 ref 和 reactive 的源码,以揭示其实现原理。

二、ref 的源码解析

2.1 基本使用回顾

在正式分析源码前,先回顾下 ref 的基本使用方式:




2.2 源码实现

在 Vue 3 的源码中,ref 函数的实现如下:

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 {
  private _value: T;
  private _rawValue: T;

  public readonly __v_isRef = true;

  constructor(value: T, public readonly _shallow: boolean) {
    this._rawValue = _shallow ? value : toRaw(value);
    this._value = _shallow ? value : toReactive(value);
  }

  get value() {
    trackRefValue(this);
    return this._value;
  }

  set value(newVal) {
    const useDirectValue = this._shallow || isShallow(newVal) || isReadonly(newVal);
    newVal = useDirectValue ? newVal : toRaw(newVal);
    if (hasChanged(newVal, this._rawValue)) {
      this._rawValue = newVal;
      this._value = useDirectValue ? newVal : toReactive(newVal);
      triggerRefValue(this, newVal);
    }
  }
}
源码解释
  1. ref 函数:它调用 createRef 函数来创建 ref 对象。
  2. createRef 函数:先检查传入的值是否已经是 ref 对象,若是则直接返回,否则创建一个 RefImpl 实例。
  3. RefImpl 类
    • _value 和 _rawValue_rawValue 存储原始值,_value 存储响应式的值。
    • __v_isRef:用于标记这是一个 ref 对象。
    • get value():访问 ref 的值时,会调用 trackRefValue 进行依赖收集。
    • set value():设置 ref 的值时,会先判断新值是否与旧值不同,若不同则更新 _rawValue 和 _value,并调用 triggerRefValue 触发依赖更新。

三、reactive 的源码解析

3.1 基本使用回顾




3.2 源码实现

function reactive(target: object) {
  if (isReadonly(target)) {
    return target;
  }
  return createReactiveObject(
    target,
    false,
    mutableHandlers,
    mutableCollectionHandlers
  );
}

function createReactiveObject(
  target: Target,
  isReadonly: boolean,
  baseHandlers: ProxyHandler,
  collectionHandlers: ProxyHandler
) {
  if (!isObject(target)) {
    if (__DEV__) {
      console.warn(`value cannot be made reactive: ${String(target)}`);
    }
    return target;
  }
  if (target[ReactiveFlags.RAW] && !(isReadonly && target[ReactiveFlags.IS_REACTIVE])) {
    return target;
  }
  const proxy = new Proxy(
    target,
    targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers
  );
  return proxy;
}
源码解释
  1. reactive 函数:先检查目标对象是否为只读对象,若是则直接返回,否则调用 createReactiveObject 函数创建响应式对象。
  2. createReactiveObject 函数
    • 检查目标是否为对象,若不是则给出警告并返回原目标。
    • 检查目标对象是否已经是响应式对象,若是则直接返回。
    • 使用 Proxy 创建一个代理对象,根据目标对象的类型选择不同的处理程序。

四、ref 和 reactive 的区别与联系

4.1 区别

  • 数据类型ref 可用于基本数据类型和对象,而 reactive 主要用于对象和数组。
  • 访问方式:访问 ref 的值需通过 .value 属性,而 reactive 对象可直接访问属性。
  • 实现方式ref 基于 RefImpl 类实现,reactive 基于 Proxy 实现。

4.2 联系

  • 转换:可通过 toRefs 将 reactive 对象转换为多个 ref 对象。
  • 共同构建响应式系统:二者都是 Vue 3 响应式系统的重要组成部分,协同工作以实现数据的响应式更新。

五、总结

通过对 ref 和 reactive 源码的深入分析,我们了解到它们的实现原理。ref 借助 RefImpl 类和 getter/setter 进行依赖收集和触发更新,reactive 则利用 Proxy 对对象的属性访问和修改进行拦截。理解这些源码有助于我们更好地运用 ref 和 reactive,避免常见的错误,从而构建出高效、稳定的 Vue 3 应用。

到这里,这篇文章就和大家说再见啦!我的过往文章里还藏着许多干货,感兴趣的话也可以点击我的主页看看,下面的文章也很精彩,可别错过。创作这篇内容花费了不少心血,要是它帮你解决了问题,或者带来了启发,就多多支持下 “码上前端” 吧~要是想转载,麻烦一定注明本文链接,感谢大家!

你可能感兴趣的:(vue.js,node.js,javascript,前端框架,前端,ref,reactive)