【Vue3 易混淆概念点一】ref、toRef、toRefs、reactive 异同点

数字化管理平台
Vue3+Vite+VueRouter+Pinia+Axios+ElementPlus
权限系统-商城
个人博客地址

一、ref、toRef、toRefs 异同点

  • ref、toRef、toRefs 函数都可以将某个对象中的属性变成响应式数据

  • ref 函数的本质是拷贝,修改响应式数据,不会影响到原始数据(引用数据类型会有影响),视图会更新

  • toRef、toRefs 函数和传入的数据形成引用关系,修改 toRef 会影响这些数据,但是不会更新视图

    作用:把一个响应式对象转换成普通对象,该普通对象的每个属性都是一个 ref

    • toRef 函数一次仅能设置一个数据,接收两个参数,第一个参数是哪个对象,第二个参数是对象的哪个属性
    • toRefs 函数接收一个对象作为参数,它会遍历对象身上的所有属性,然后挨个调用 toRef 执行。用于批量设置多个数据为响应式
  • ref 数据会引起监听行为,而 toRef 不会

<script setup>
    const state = reactive({
        title: '标题',
        name: 'wff'
    })
    const { title } = toRefs(state)
    const name = toRef(state, 'name')

    console.log(state.title)
    console.log(title.value)
    console.log(name.value)

    const titleState = ref('new')
    const count = ref({
        count: 0
    })
</script>

<template>
  <div>
    name:{{name}}
  </div>
</template>

注:我们使用 reactive创建的对象,如果想在模板中使用,就必须得使用 xxx.xxx的形式;如果大量用到的话还是很麻烦的,但是使用 es6解构以后,会失去响应式。那么toRefs的作用就体现在这,利用toRefs可以将一个响应式 reactive 对象的所有原始属性转换为响应式的ref属性

二、ref 和 reactive 的区别

  • ref 函数和 reactive 函数都是用来定义响应式数据的。

  • ref 函数更适合定义基本数据类型(可接收基本数据类型和对象)

    • 函数参数可以是基本数据类型,也可以接受对象类型

    • 如果参数是对象类型时,其实底层的本质还是 reactive,系统会自动给 ref 传入的值进行转换

      ref(1) -> reactive({value:1})
      # ref函数只能操作浅层次的数据,把基本数据类型当作自己的属性值;深层次依赖于reactive
      
    • 在 template 中访问,系统会自动添加 .value 。在 js 中需要手动 .value 进行访问

      import { ref } from 'vue'
      
      // 为基本数据类型添加响应式状态
      const name = ref('Neo')
      
      // 为复杂数据类型添加响应式状态
      const state = ref({
        count: 0
      })
      
      // 打印name的值
      console.log(name.value)
      // 打印count的值
      console.log(state.value.count)
      
    • ref 响应式原理是依赖于Object.defineProperty()get()set()

    • ref 用于获取 dom 节点

      Vue2中我们通过this.$refs来获取dom节点,但Vue3组合式API中我们需要通过ref来获取节点元素

      首先需要在标签上添加 ref='xxx',然后再setup中定义一个初始值为nullref类型,名字要和标签的ref属性一致

      <script setup>
      import { onMounted, ref } from 'vue';
      // 利用ref函数获取组件中的标签元素功能实现需求: 让输入框自动获取焦点
      const inputRef = ref(null);
      
      ;(() => {
         inputRef.value && inputRef.value.focus()
      })();
      </script>
      
      <template>
          <h2>App</h2>
          <input type="text" ref="inputRef">
      </template>
      

      ref 接受的数据类型:基本类型,引用类型。

      作用:把参数加工成一个响应式对象,全称为reference对象(简称为ref对象) 。

      核心原理:如果参数是基本类型那么形成响应式依赖于Object.defineProperty( )的get( )和set( ),如果ref的参数是引用类型,底层ref会借助reactive的proxy 定义响应式变成这样:reactive({value:‘xiaxia’})。

  • reactive 函数更适合定义复杂的数据类型(json/arr)

    • 它的响应式是更加‘深层次’的(会影响对象内部所有嵌套的属性,所有的数据都是响应式的),底层本质是将传入的数据包装成一个 Proxy

    • 参数必须是对象或者数组,如果要让对象的某个元素实现响应式时比较麻烦。需要使用 toRefs 函数处理

    • 获取数据值的时候直接获取,不需要加.value

      import { reactive } from 'vue'
      
      // 响应式状态
      const state = reactive({
        count: 0
      })
      
      // 打印count的值
      console.log(state.count)
      

附录:

ref 介绍

  • ref() 方法接受一个内部值,返回一个响应式的、可更改的 ref 对象,此对象只有一个指向其内部值的属性 .value

    ref 对象是可更改的,也就是说你可以为 .value 赋予新的值。它也是响应式的,即所有对 .value 的操作都将被追踪,并且写操作会触发与之相关的副作用。

    如果将一个对象赋值给 ref,那么这个对象将通过 reactive() 转为具有深层次响应式的对象。这也意味着如果对象中包含了嵌套的 ref,它们将被深层地解包。

    若要避免这种深层次的转换,请使用 shallowRef() 来替代。

    相较于reactive包裹对象完成响应式,ref更具优势,因为当改变reactive中保存的对象的内存地址时(也就是换一个全新的对象),由于vue3的响应式是通过创建代理对象,在代理对象的set方法中放入该实例的渲染函数的方法构建的,而替换整个对象,而不是修改对象内部的属性值,其并不会调用set方法,所以页面并不会响应式,但是如果使用ref包裹对象,那么此对象仅仅是ref对象的一个value属性,所以更改内存地址时,也仅仅是修改ref对象的value属性,依然会调用代理对象的set方法,完成响应式dom更新

  • reactive() 函数用于返回一个对象的响应式代理
    reactive 函数更适合定义复杂的数据类型(json/arr/obj/map/set)**

它的响应式是更加‘深层次’的(会影响对象内部所有嵌套的属性,所有的数据都是响应式的),底层本质是将传入的数据包装成一个 JavaScript Proxy,其行为表现与一般对象相似。不同之处在于 Vue 能够跟踪对响应式对象属性的访问与更改操作。因此不等于源对象,建议只使用响应式代理,避免使用原始对象。

   import { reactive, toRefs } from 'vue'
    
    // 通过 reactive 定义响应式数据
    const state = reactive({
        // 定义每一个表单控件的配置项:type类型、label文本、prop绑定字段 等信息
        items: [{
            label: "用户名",
            prop: "name",
            inputwidth: "100%",
        }, {
            password: true,
            label: "密码",
            prop: "pwd",
            inputwidth: "100%",
            rules: [{ required: true, message: "请输入密码", trigger: 'blur' }]
        }, {
            label: "手机号",
            prop: "phone",
            inputwidth: "100%",
            required: true,
            validateType: "phone"
        }],
        // 定义每一个表单绑定字段对应的信息(form表单数据信息)
        formData: {
            name: "",
            pwd: "",
            phone: ""
        },
        // form 元素配置信息
        options: {
            size: "small",
            formWidth: "35%",//表单占父元素的宽度
            labelWidth: "80px",//标签的长度
        },
    })
    
    // 通过 toRefs 获取 reactive 中的每一项属性的引用(js中调用使用 .value,template 中直接使用自动解析)
    const { items, formData, options } = toRefs(state);
    
    console.log(items,options)
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MagnumHou

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值