浅析Vue为什么需要同时使用Ref和Reactive

 更新时间:2023年08月09日 08:44:30   作者:王大冶  
这篇文章主要想来和大家一起探讨一下Vue为什么需要同时使用Ref和Reactive,文中的示例代码简洁易懂,感兴趣的小伙伴可以跟随小编一起了解一下

在使用 Options API 工作时声明响应性数据是直截了当的。data 选项内的所有内容都会自动变为响应性,并在模板中可用。唯一需要注意的是,要将data设为一个函数,以防止在所有组件实例之间共享状态。

让我们讨论一下Vue 3中发生了什么变化,以及为什么我们需要两个不同的助手。

Vue 2中的响应性

data 组件选项内的每个属性都将通过 Object.defineProperty 转换为getter/setter。这些getter/setter对我们来说是看不见的,但在底层,它们使Vue在访问或修改属性时能够执行依赖跟踪。

每个组件都有一个关联的观察者,用于跟踪在组件的渲染周期中使用的属性。如果依赖项更新,观察者会通知组件,然后触发重新渲染。

Vue 3中的响应性

在 Vue 3 中,一切都发生了变化。核心部分从零开始重写,现在由Javascript Proxies提供响应性。Proxies是一种现代且优雅的方式来观察一个对象并在其属性被访问或更新时得到通知。

可以通过以下简单的例子来理解代理是如何工作的:

const userInfo = {
  firstName: "fotis",
  age: 35,
};
const handler = {
  get(target, property) {
    if (property === "firstName") {
      const name = target[property]
      return name.charAt(0).toUpperCase() + name.slice(1);
    }
    if (property === "age") {
      return '--'
    }
    return target[property]
  },
};
const proxy = new Proxy(userInfo, handler);
console.log(proxy.firstName) // "Fotis"
console.log(proxy.age) // "--"

处理器内部的get方法被称为陷阱,每次访问对象的属性时都会被调用。以类似的方式,可以定义一个设定的陷阱:

const userInfo = {
  firstName: "Fotis",
  age: 35,
};
const handler = {
  set(target, prop, value) {
    if (prop === "age") {
      if (!Number.isInteger(value)) {
        throw new TypeError("The age is not an integer");
      }
      if (value > 200) {
        throw new RangeError("The age seems invalid");
      }
    }
    target[prop] = value;
    return true;
  },
};
const proxy = new Proxy(userInfo, handler);
proxy.age = 12 // OK
proxy.age = 300 // Error: The age seems invalid

这正是 Vue 3 响应性背后的理念。当使用 reactive 助手声明一个变量时,会使用一个 proxy. 来跟踪任何变化。

function reactive(obj) {
  return new Proxy(obj, {
    get(target, key) {
      track(target, key)
      return target[key]
    },
    set(target, key, value) {
      target[key] = value
      trigger(target, key)
    }
  })
}

当然,响应式助手的实际实现更为复杂,能处理边缘情况,但其核心仍然使用proxy。

以上的片段解释了为什么将响应性变量解构或重新分配给本地变量后,它就不再具有反应性,因为它不再触发源对象上的 get/set proxy 陷阱。

这看起来像是一个完美的解决方案,可以使所有事物都变成响应式。但是有个问题!根据定义,proxy只适用于复杂类型。这些包括对象、数组、映射和集合。要使一个原始类型变得反应灵敏,我们仍然需要使用代理,但首先我们必须将其包装在一个对象中。

function ref(value) {
  const refObject = {
    get value() {
      track(refObject, 'value')
      return value
    },
    set value(newValue) {
      value = newValue
      trigger(refObject, 'value')
    }
  }
  return refObject
}

这解释了为什么必须在 script setup 中使用烦人的 .value 。而且,再次重构或重新分配给本地变量也是行不通的。

总结

那么,为什么需要 Ref 和 Reactive的答案是:Proxy。对于复杂类型,它们可以直接使用,但对于原始类型,需要创建一个代理对象。

希望,理解Vue的内部工作原理可以使你更有效,并且可以消除 refreactive 之间的任何混淆。

以上就是浅析Vue为什么需要同时使用Ref和Reactive的详细内容,更多关于Vue Ref Reactive的资料请关注脚本之家其它相关文章!

相关文章

  • Vue3 Hooks 模块化抽离示例详解

    Vue3 Hooks 模块化抽离示例详解

    这篇文章主要为大家介绍了Vue3 Hooks 模块化抽离示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-09-09
  • vue+animation实现翻页动画

    vue+animation实现翻页动画

    这篇文章主要为大家详细介绍了vue+animation实现翻页动画,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-06-06
  • 在vue里使用codemirror遇到的问题

    在vue里使用codemirror遇到的问题

    这篇文章主要介绍了在vue里使用codemirror遇到问题,本文给大家记录下来了,需要的朋友可以参考下
    2018-11-11
  • Vue 实现列表动态添加和删除的两种方法小结

    Vue 实现列表动态添加和删除的两种方法小结

    今天小编就为大家分享一篇Vue 实现列表动态添加和删除的两种方法小结,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-09-09
  • vue从使用到源码实现教程详解

    vue从使用到源码实现教程详解

    这篇文章主要介绍了vue从使用到源码实现的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2016-09-09
  • 基于Vue.js的表格分页组件

    基于Vue.js的表格分页组件

    这篇文章主要为大家详细介绍了基于Vue.js的表格分页组件使用方法,了解了Vue.js的特点,感兴趣的朋友可以参考一下
    2016-05-05
  • 使用Vant框架list组件遇到的坑及解决

    使用Vant框架list组件遇到的坑及解决

    这篇文章主要介绍了使用Vant框架list组件遇到的坑及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-04-04
  • 解决vue中this.$set()不更新问题

    解决vue中this.$set()不更新问题

    我在做一个附件删除功能的时候发现,明明打印出来附件已经没有数据了但是页面就是不刷新, this.$set()不生效,所以本文小编给大家介绍了vue中this.$set()不更新的解决方法,需要的朋友可以参考下
    2023-11-11
  • vue+element_ui上传文件,并传递额外参数操作

    vue+element_ui上传文件,并传递额外参数操作

    这篇文章主要介绍了vue+element_ui上传文件,并传递额外参数操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • Vue+axios 实现http拦截及路由拦截实例

    Vue+axios 实现http拦截及路由拦截实例

    这篇文章主要介绍了Vue+axios 实现http拦截及路由拦截 ,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-04-04

最新评论