博客
关于我
Vue.js 学习总结(14)—— Vue3 为什么推荐使用 ref 而不是 reactive
阅读量:796 次
发布时间:2023-02-17

本文共 2516 字,大约阅读时间需要 8 分钟。

Vue3 中 ref 和 reactive 的对比:深入理解两者的区别与优势

Vue3 中的响应式数据处理通过两个核心 API——refreactive ——实现。虽然两者都能用于管理响应式状态,但它们的实现方式和适用场景有本质区别。本文将从源码角度深入分析两者的工作原理,并探讨为什么 Vue3 官方推荐使用 ref 而非 reactive


ref 的内部工作原理

ref 是一个函数,接受一个内部值并返回一个响应式且可变的引用对象。这个引用对象有一个 .value 属性,指向内部值。ref 的核心在于返回一个 RefImpl 实例,这个实例通过 getter 和 setter 方法实现了响应式的数据追踪和更新。

RefImpl 实现细节

RefImpl 类的构造函数接受一个初始值,并创建一个包含以下组件的对象:

  • 内部值 (_value):存储传递的初始值。
  • 依赖管理 (_dep):通过 Dep 类管理依赖关系,用于追踪和通知所有依赖于当前 Ref 对象的效果(如计算属性或副作用函数)。
  • 响应式处理:通过 toReactive 函数将值转换为响应式对象。对于基础数据类型,直接返回原始值;对于对象和数组,则通过 reactive 创建响应式代理后再包装。
  • RefImplvalue getter 方法通过 trackRefValue 进行依赖收集,确保当 Ref 的值发生变化时,依赖它的组件或副作用函数能够重新运行。value setter 方法则通过 set 方法触发更新,通知所有依赖并更新相关状态。

    ref 的使用示例

    import { ref } from 'vue';
    let state = ref({ count: 0 });
    state.value.count++;

    reactive 的内部工作原理

    reactive 函数通过创建一个 Proxy 对象来实现响应式数据的代理。Proxy 会拦截对目标对象的操作,从而实现对数据变化的响应式追踪。源码中,reactive 的实现步骤如下:

  • 检查是否已是响应式对象:如果传入的目标对象已经是响应式对象,则直接返回它。
  • 创建响应式代理:调用 createReactiveObject 函数创建一个 Proxy 实例,并注册相关的依赖和更新机制。
  • reactive 的局限性

    尽管 reactive 通过 Proxy 实现了响应式,但它存在一些重要的局限性:

  • 仅适用于引用数据类型reactive 主要针对对象(包括数组和集合)有效,对基础数据类型(如 stringnumberboolean)无效。

    import { reactive } from 'vue';
    const state = reactive({ count: 0 });
    // count 为响应式属性

    如果尝试用基础数据类型:

    import { reactive } from 'vue';
    const state = reactive(123);
    // state 是非响应式对象
  • 赋值和解构操作容易失去响应性

    • 直接赋值:将响应式对象赋值给变量会失去响应性。
      import { reactive } from 'vue';
      let state = reactive({ count: 0 });
      state = { count: 1 };// 失去响应性
    • 直接解构:解构响应式对象的属性会得到非响应式变量。
      import { reactive } from 'vue';
      const state = reactive({ count: 0 });
      let { count } = state;
      count++; // count 仍为 0
  • 属性赋值会失去响应性

    import { reactive } from 'vue';
    let state = reactive({ count: 0 });
    let count = state.count; // count 为非响应式变量

  • 为什么推荐使用 ref?

    ref 提供了一种更加统一和灵活的响应式解决方案,避免了 reactive 的局限性。以下是推荐使用 ref 的几个关键原因:

  • 统一性ref 适用于所有数据类型,包括基础数据类型和复杂对象,简化了开发者的代码书写。
    import { ref } from 'vue';
    let num = ref(0);
    let str = ref('Hello');
    let obj = ref({ count: 0 });
  • 深层响应性ref 支持对嵌套对象和数组的深层追踪和更新。
    import { ref } from 'vue';
    let obj = ref({ user: { details: { age: 18 } } });
    obj.value.user.details.age++;
  • 灵活性ref 在处理普通赋值和复杂操作方面表现优异,支持对象的替换、属性的增删和动态更新。
    import { ref } from 'vue';
    let state = ref({ count: 0, name: 'Vue' });
    state.value = { count: 10, name: 'Vue 4' };
    state.value.count = 20;
    state.value.name = 'Vue 5';
    state.value.newProperty = 'New Property';
    delete state.value.newProperty;
  • 避免依赖代理的复杂性ref 的实现简单明了,避免了 reactive Proxy 的性能开销和复杂性。

  • 总结

    ref 在 Vue3 中提供了一种更统一、灵活的响应式解决方案,适用于所有类型的数据。相比之下,reactive 虽然也能实现响应式,但在数据类型局限性和赋值操作上存在明显不足。因此,推荐使用 ref 来处理 Vue3 的响应式数据,既简化了代码编写,也提升了开发体验。

    转载地址:http://wunfk.baihongyu.com/

    你可能感兴趣的文章
    numpy中的argsort的用法
    查看>>
    NumPy中的精度:比较数字时的问题
    查看>>
    numpy判断对应位置是否相等,all、any的使用
    查看>>
    Numpy多项式.Polynomial.fit()给出的系数与多项式.Polyfit()不同
    查看>>
    Numpy如何使用np.umprod重写range函数中i的python
    查看>>
    numpy学习笔记3-array切片
    查看>>
    numpy数组替换其中的值(如1替换为255)
    查看>>
    numpy数组索引-ChatGPT4o作答
    查看>>
    numpy最大值和最大值索引
    查看>>
    NUMPY矢量化np.prod不能构造具有超过32个操作数的ufunc
    查看>>
    Numpy矩阵与通用函数
    查看>>
    numpy绘制热力图
    查看>>
    numpy转PIL 报错TypeError: Cannot handle this data type
    查看>>
    Numpy闯关100题,我闯了95关,你呢?
    查看>>
    nump模块
    查看>>
    Nutch + solr 这个配合不错哦
    查看>>
    NuttX 构建系统
    查看>>
    NutUI:京东风格的轻量级 Vue 组件库
    查看>>
    NutzCodeInsight 2.0.7 发布,为 nutz-sqltpl 提供友好的 ide 支持
    查看>>
    NutzWk 5.1.5 发布,Java 微服务分布式开发框架
    查看>>