一步步从Vue3.x源码上理解ref和reactive的区别

当我们在使用Vue3.x的时候,ref和reactive这两个API很常用,但是也经常容易搞混。这篇攻略将介绍ref和 reactive的区别,并且通过源码分析来更加深刻理解这两者之间的差异。

1. reactive

reactive是用于将对象转为响应式的API。我们一般使用这个API来将普通的对象转成可以响应式地监听的对象。使用方法如下所示:

import { reactive } from 'vue'

const reactiveObject = reactive({
  count: 1
})

从上面的代码中,我们可以看出,将对象传给 reactive()后会返回一个通过 Proxy实现的响应式对象,而这个响应式对象可以监听到它自身属性的变化。

2. ref

ref是用来定义一个响应式数据的API。如果我们的目标只是一个基本类型的变量或者只需要进行单向绑定,则可以选择使用ref。下面是使用ref的例子:

import { ref } from 'vue'

const count = ref(1)

从上面代码中,我们可以看出,ref会接收一个基本类型的数据,例如数值、字符串等,然后返回一个响应式对象。这个响应式对象有一个 .value的属性,通过 .value属性获取到的就是我们传入ref()的值。

3. ref和reactive的区别

  • ref是针对基本类型变量的响应式处理,reactive是针对对象类型的响应式处理。
  • ref返回的对象具有 .value 属性,而reactive返回整个对象。
  • ref可以修改基本类型的值,而reactive不能直接修改对象属性的值,只能使用 .value或者 toRefs来修改。

下面通过源代码来进一步理解这两者的区别。

import { ref, reactive } from 'vue'

const stateA = {
  count1: ref(1),
  count2: 2,
  countObj: reactive({
    count: 3
  })
}

stateA.count1++  // 可以直接修改数值类型

stateA.count2++  // 修改会报错,需要使用reactive

stateA.countObj.count++  // 可以直接修改reactive对象属性

通过上面这段代码可以看出,在对象中,对象属性的直接修改仅仅适用于reactive对象,而针对基本类型的变量则可以使用ref。至于为什么可以这样,我们可以通过源码来分析。

4. 源码分析

首先我们来看ref的源码:

export function ref(value) {
  // 对基本类型的值进行处理
  return createRef(value)
}

function createRef(rawValue, shallow = false) {
  if (isRef(rawValue)) {
    return rawValue
  }
  const value = shallow ? rawValue : convert(rawValue)
  const runner = effect(() => {
    if (!isRef(runner)) {
      runner.value = value.value
    }
  }, {
    lazy: true,
    scheduler: shallow ? () => {} : triggerRef
  })
  const ref = {
    _isRef: true,
    get value() {
      trackRefValue(ref)
      return value
    },
    set value(newVal) {
      if (hasChanged(toRaw(newVal), rawValue)) {
        rawValue = newVal
        value.value = shallow ? newVal : convert(newVal).value
        triggerRef(ref)
      }
    }
  }
  return ref
}

从源码中可以看到,ref是通过 createRef 实现的,这个函数是设置基础类型数据的响应式的。

然后我们看reactive 的源码:

export function reactive(target) {
  if (target && target._isReadonly) {
    return target
  }
  // 如果target已经被处理过为响应式的,则直接返回target
  if (reactiveMap.has(target)) {
    return reactiveMap.get(target)
  }
  // 如果target是ref,则直接返回.value对应的响应式对象
  if (target && target.__v_isRef) {
    return reactive(target.value)
  }
  const observed = new Proxy(target, baseHandlers)
  reactiveMap.set(target, observed)
  return observed
}

从源码中可以看到,reactive 是通过创建新的 Proxy 对象来实现对象的响应式的。当 getset对象属性时,替换成监听 tracktrigger

基于这些源代码,我们可以得出refreactive的差异:

  • ref创建了一个对象,并通过这个对象的getter和setter来监听反应式数据的变化;
  • Reactive将一个对象变为响应式对象,并将其对象的所有属性都转为getter和setter来监听反应式数据的变化;

这就是ref和reactive之间的区别。对于基础类型数据,可以使用ref进行设置响应式;对于对象类型数据可以使用reactive设置响应式。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:一步步从Vue3.x源码上理解ref和reactive的区别 - Python技术站

(0)
上一篇 2023年5月28日
下一篇 2023年5月28日

相关文章

  • Vue.js学习之计算属性

    下面是关于”Vue.js学习之计算属性”的完整攻略。 什么是计算属性 在Vue.js中,我们经常需要根据已经存在的数据,通过一些复杂的逻辑计算出新的值,然后再去渲染页面。 Vue.js提供了计算属性(computed)来方便我们实现这个需求。计算属性本质上是一个方法,它可以接收已经存在的数据为参数,然后根据这些数据进行计算,最终返回一个新的值。 一个计算属性…

    Vue 2023年5月27日
    00
  • 详解vue数据响应式原理之数组

    详解Vue数据响应式原理之数组 什么是Vue数据响应式? Vue.js是一款MVVM框架,它通过数据绑定和组件化来构建用户界面。Vue的核心是将DOM和数据进行绑定,当数据发生变化时,DOM会自动更新,这就是Vue的数据响应式。 数组响应式的特殊性 数组在JS中是引用类型,当我们对一个数组进行变更时,比如push、pop、splice等操作,Vue是无法检测…

    Vue 2023年5月28日
    00
  • Vue异步更新DOM及$nextTick执行机制解读

    Vue异步更新DOM及$nextTick执行机制解读 在 Vue 中,DOM 更新并不是同步执行的,除非使用 this.$nextTick 方法,它可以保证在本次 DOM 更新后执行回调函数,下面我就来详细解读这个机制。 异步更新DOM Vue 在进行 DOM 更新时,通常借助浏览器的异步更新机制,将多个数据变更合并为一次更新,以提高更新效率。这个机制体现在…

    Vue 2023年5月29日
    00
  • vue上传文件formData入参为空,接口请求500的解决

    针对”vue上传文件formData入参为空,接口请求500″这一问题,可以按照以下步骤来进行排查和解决: 1.确保上传接口正确 首先需要确认上传接口是否能够正常处理上传请求,可以使用其他工具或方式来简单测试上传接口是否正常。如果上传接口正确无误,那么可以继续下一步排查。 2.确认请求头信息 当使用formData方式上传文件时,需要设置请求头信息,其中包括…

    Vue 2023年5月28日
    00
  • 关于vue-cli 3配置打包优化要点(推荐)

    我来详细讲解一下关于Vue-CLI 3的打包优化要点。 1. 配置文件 Vue-CLI 3的配置文件是通过vue.config.js文件进行配置的。我们可以在这里设置打包的基本配置、压缩代码、CDN等。 2. 代码分割 代码分割是优化打包体积的一个非常重要的方式。一般来说,我们可以通过以下方式进行代码分割: 异步组件:在路由懒加载、组件懒加载的时候使用imp…

    Vue 2023年5月29日
    00
  • 使用Vue.set()方法实现响应式修改数组数据步骤

    使用Vue.set()方法实现响应式修改数组数据,可以确保视图与数据的同步更新。下面是实现步骤: 引入Vue 在使用Vue.set()方法之前,需要先在项目中引入Vue.js。可以通过script标签引入,也可以通过webpack等构建工具引入。 定义数据 假设要在Vue组件中使用一个数组todos: data() { return { todos: [ {…

    Vue 2023年5月28日
    00
  • 利用vue3仿苹果系统侧边消息提示效果实例

    下面我就给您详细讲解利用vue3仿苹果系统侧边消息提示效果的完整攻略。 1. 概述 本文将介绍如何利用vue3实现仿苹果系统侧边消息提示效果。为了达到这个目的,我们将使用一些vue3的特性,如Teleport,Composition API等。 2. 准备工作 在正式开始实现之前,我们需要完成一些准备工作。 2.1 创建项目 首先,我们需要创建一个新的vue…

    Vue 2023年5月28日
    00
  • vue学习笔记之指令v-text && v-html && v-bind详解

    针对“vue学习笔记之指令v-text && v-html && v-bind详解”,我来给你详细讲解一下。 一、v-text指令 1.1 v-text定义 v-text指令用于在Vue模板中更新元素的文本内容。它会替换元素的textContent,但是不会解析其中的HTML标签。 1.2 v-text使用示例 下面是一个简单…

    Vue 2023年5月27日
    00
合作推广
合作推广
分享本页
返回顶部