reactive和ref的异同、toRef和toRefs的使用

Vue3中的reactive与ref:响应式数据处理与优化,
本文比较了Vue3中的reactive和ref在处理响应式数据方面的异同,强调了ref在处理基本类型和单一值的优势,以及toRef和toRefs在提升数据操作性能和直观性的作用。

一、reactive和ref

有了reactive为什么还要ref?

ref处理起基本数据类型来更加的方便快捷,性能要更好。

ref 内部值的变化只会触发订阅它的副作用函数(effect)更新,而 reactive(Proxy) 内部对象的任何属性变化都会触发整个对象的重新渲染。

相同点:

  1. 都是 Vue 3 提供的用于创建响应式数据的函数;
  2. 在组件中都能够触发视图更新,实现数据的双向绑定。

不同点:

  1. 数据类型

    • reactive:主要用于处理对象或数组等复杂数据类型,将整个对象转为响应式对象;
    • ref:主要用于处理基本类型数据(如数字、字符串等)或单一值,将单一值转为响应式数据。
  2. 使用方式

    • reactive:接收一个普通对象作为参数,并返回一个包含响应式数据的代理对象。

      import { reactive } from 'vue';
      
      const state = reactive({
          count: 0
      });
      
    • ref:接收一个初始值作为参数,并返回一个包含响应式数据的引用对象。

      import { ref } from 'vue';
      
      const count = ref(0);
      
  3. 访问方式

    • reactive:直接通过对象属性访问。

      state.count++;
      
    • ref:需要通过 .value 属性来访问或修改值。

      count.value++;
      
  4. 特殊情况

    • ref 对象是通过 .value 来访问内部值的;而 reactive 返回的代理对象可以直接访问属性值。
    • 当需要监听一个基本类型的值时,通常会使用 ref;当需要监听一个对象或数组的多个属性时,使用 reactive 更方便。

ref里面放对象或者数组也是合法的,但可能会出现以下问题,所以最好还是用reactive。

  1. 内部值访问:由于 ref 对象内部的值是通过 .value 属性来访问的,因此如果你这样创建了一个 ref 对象:const myRef = ref({val: 1}),那么在访问该对象的值时需要通过 myRef.value.val 来获取属性值,这会使代码显得冗长和不够直观。

  2. 响应性ref 主要用于处理基本类型数据或单一值,而不是复杂对象。当使用 ref({val: 1}) 创建一个 ref 对象时,其内部的对象可能不会被完全响应化,即对象内部属性的变化可能不会触发视图更新。

  3. 深度监听:Vue 的响应式系统不会对对象进行深度监听,即对象内部嵌套的对象或数组的变化不会被自动追踪。因此,如果 ref 内部的对象包含深层次的属性,可能会导致部分属性的变化无法被及时监听到。

二、toRef / toRefs

作用
toRef 和 toRefs 可以用来复制 reactive 里面的属性然后转成 ref,而且它既保留了响应式,也保留了引用,也就是你从 reactive 复制过来的属性进行修改后,除了视图会更新,原有 ractive 里面对应的值也会跟着更新,浅拷贝,它复制的其实就是引用 + 响应式 ref。(这样的转换可以提高数据响应式的性能,使数据的访问和操作更加方便和直观)

不加 s 和 加 s 的区别就是这样:

toRef: 复制 reactive 里的单个属性并转成 ref;
toRefs: 复制 reactive 里的所有属性并转成 ref。

使用方式 

toRef

<template>
  <h2>
    reactive-greet: {{ info.greet }} 
  </h2>
  <h2>
    toRef-greet: {{ rGreet }}
  </h2>
  <button @click="onChangeGreet">更换问候语</button>
</template>
 
<script>
import { reactive, toRef } from 'vue'
export default {
	setup() {
    let info = reactive({
      name: 'Tony',
      greet: 'Hello'
    })
	// 复制 info 里的 greet 属性
    let rGreet = toRef(info, 'greet')
    // 更改 rGreet
    const onChangeGreet = () => {
      rGreet.value = 'world!'
    }
    return {
      info,
      rGreet,
      onChangeGreet
    }
  }
}
</script>

 更改 rRgeet 的同时更改了原有的 info.greet 属性

 toRefs

<template>
  <h2>
    reactive-info-greet: {{ info.greet }} 
  </h2>
  // 要带上 .value
  <h2>
    toRefs-rInfo-greet: {{ rInfo.greet.value }}
  </h2>
  <button @click="onChangeGreet">更新</button>
</template>
 
<script>
import { reactive, toRefs } from 'vue'
export default {
	setup() {
    let info = reactive({
      name: 'Tony',
      greet: 'Hello'
    })
	// 复制整个 info
    let rInfo = toRefs(info)
    // 更改 rInfo.greet
    const onChangeGreet = () => {
      rInfo.greet.value = 'world!'
    }
    return {
      info,
      rInfo,
      onChangeGreet
    }
  }
}
</script>

Vue 3 的响应式系统中,`ref`、`reactive`、`toRef` `toRefs` 是构建响应式数据的核心工具。它们各自有不同的用途适用场景,理解它们之间的区别有助于更高效地进行开发。 ### `ref` `ref` 是一个函数,用于创建一个响应式的引用对象。它通常用于包装基本数据类型(如字符串、数字等),也可以用于包装对象。当使用 `ref` 创建响应式数据时,返回的值是一个带有 `.value` 属性的对象,该属性用于访问或修改数据的值。 ```javascript import { ref } from 'vue'; const count = ref(0); console.log(count.value); // 输出: 0 count.value++; console.log(count.value); // 输出: 1 ``` `ref` 的一个显著特点是它可以保持对基本数据类型的响应性,这在 Vue 的模板中直接使用时非常方便。由于其 `.value` 特性,它非常适合用于逻辑拆分业务解耦的场景[^3]。 ### `reactive` `reactive` 函数用于创建一个响应式的对象。它接受一个普通对象作为参数,并返回该对象的响应式代理。与 `ref` 不同的是,使用 `reactive` 创建的响应式对象不需要通过 `.value` 来访问属性值。 ```javascript import { reactive } from 'vue'; const state = reactive({ count: 0 }); console.log(state.count); // 输出: 0 state.count++; console.log(state.count); // 输出: 1 ``` `reactive` 更适合用于处理复杂的对象结构,因为它能够自动追踪对象内部的变化,并且在模板中使用时更加直观。 ### `toRef` `toRef` 用于为源响应式对象上的某个属性创建一个新的 `ref`。这个新的 `ref` 保持了与源对象属性之间的响应式连接。这意味着如果源对象的属性发生变化,通过 `toRef` 创建的 `ref` 也会更新,反之亦然。 ```javascript import { reactive, toRef } from 'vue'; const state = reactive({ foo: 1 }); const fooRef = toRef(state, 'foo'); fooRef.value++; console.log(state.foo); // 输出: 2 ``` `toRef` 在处理从父组件传递过来的 `props` 时特别有用,尤其是在需要引用 `props` 中的某个特定属性并保持其响应性的情况下[^4]。 ### `toRefs` `toRefs` 函数的作用是将一个响应式对象转换成一个普通对象,其中每个属性都是一个 `ref`。这样做的好处是可以方便地对响应式对象进行解构,同时保持各个属性的响应性。 ```javascript import { reactive, toRefs } from 'vue'; const state = reactive({ count: 0, name: 'Vue' }); const { count, name } = toRefs(state); count.value++; console.log(state.count); // 输出: 1 name.value = 'Vue 3'; console.log(state.name); // 输出: Vue 3 ``` `toRefs` 特别适用于需要将响应式对象的多个属性作为独立的 `ref` 使用的情况,例如在组合函数中返回多个响应式值时[^5]。 ### 使用场景对比 - **`ref`**:适用于需要保持基本数据类型响应性的场景,或者需要封装逻辑时。 - **`reactive`**:适用于处理复杂对象结构,提供更直观的 API。 - **`toRef`**:适用于需要从现有响应式对象中提取单个属性并保持其响应性的场景。 - **`toRefs`**:适用于需要解构响应式对象的同时保持其属性响应性的场景。 通过合理选择使用这些工具,可以更有效地构建 Vue 3 应用程序中的响应式数据流。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值