花几分钟搞懂 toRef 和 toRefs !!

1,621 阅读3分钟

首先我们先介绍他们是什么???

在 Vue 中,toReftoRefs都是用于处理响应式数据的工具函数。

  • toRefs主要用于将一个响应式对象转换为一组响应式引用对象。这样做的好处在于,当你需要解构一个响应式对象时,使用toRefs可以确保解构后的属性仍然保持响应式。
  • toRef允许从一个已有的响应式对象中创建一个对特定属性的响应式引用。这个引用会保持与源对象属性的响应式连接,即当源对象的属性值发生变化时,通过toRef创建的引用也会同步更新。

image.png

image.png 上面的图片是Vue官方文档给出的解释,toRefs的实现一定程度是基于toRef上的,下面我们一起通过代码实例来理解这两个APi吧!

🐟toRefs

<template>
  <div>
    <h2> 姓名:{{ perosn.name }}</h2>
    <h2> 年龄:{{ person.age }}</h2>
    <button @click="changeName">增加~</button>
    <button @click="changeAge">加一</button>
  </div>
</template>

<script setup>
import { reactive } from 'vue'
let person = reactive({
  name: '张三',
  age: 18
})
const changeAge = () => {
  person.age += 1
}
const changeName = () => {
  person.name += '!'
}
</script>
<style lang="scss" scoped></style>

这段函数定义了一个含有属性nameagePerson对象,并且定义了两个button去修改nameage. 如果在这个时候你想使用解构赋值,将person中的name和age提取出来,

let { name, age } = person

是否这个时候我们就可以通过解构出来的age和person,不需要再使用前缀Person去调用了,

<template>
  <div>
    <h2> 姓名:{{ name }}</h2>
    <h2> 年龄:{{ age }}</h2>
    <button @click="changeName">增加~</button>
    <button @click="changeAge">加一</button>
  </div>
</template>
<script setup>
import { ref, reactive } from 'vue'
let person = reactive({
  name: '张三',
  age: 18
})
let { name, age } = person
const changeAge = () => {
  age += 1
  console.log(age);
}
const changeName = () => {
  name += '!'
  console.log(name);
}
</script>
<style lang="scss" scoped></style>

你会发现视图界面并没有更新,但是我在函数里写的console.log(age)console.log(name)他们的输出会随着函数的调用而改变,说明agename并不是没有改变,而是person.age``person.name没有改变,因为person才是响应式对象,而当对一个对象进行解构赋值时,会创建新的变量来引用对象的属性值。如果修改这些新变量的值,不会直接影响原始对象。所以就能很好的解释为什么 age,name的值明明改变了但是为什么视图界面不更新的原因.

这个时候Vue就提供api让我们去解决这个问题 首先我们介绍toRefs,看下面一段代码

<template>
  <div>
    <h2> 姓名:{{ name }}</h2>
    <h2> 年龄:{{ age }}</h2>
    <button @click="changeName">增加~</button>
    <button @click="changeAge">加一</button>
  </div>
</template>
<script setup>
import { toRefs, reactive } from 'vue'
let person = reactive({
  name: '张三',
  age: 18
})
let { name, age } = toRefs(person)
const changeAge = () => {
  age.value += 1
  console.log(age);
}
const changeName = () => {

  name.value += '!'
  console.log(name);
}
</script>
<style lang="scss" scoped></style>

我们在解构赋值的时候给person加上了toRefs,顾名思义,toRefs就是让解构出来的值变成ref所定义的响应式数据,所以需要加上value去修改他的值,console.log()出来的agename也验证了我们的想法

image.png 我们把 let { name, age } = toRefs(person)这行改为 let x = toRefs(person) ,然后输出一下 x image.png 这个时候我们就可以理解上面说将一个响应式对象转换为一组响应式引用对象

🐟toRef

接下来我们介绍一下toRef,toRefs是把person这个响应式对象所有的key:value一次性都取出来,赋予响应式能力,toRef比他少了一个s,所以他是创建一个对特定属性的响应式引用,老规矩还是来看一段代码

  • 例如,假设有一个响应式对象person = reactive({ name: '张三', age: 18 }),可以使用const nameRef = toRef(person, 'name')创建一个对person对象中name属性的引用。
<template>
  <div>
    <p>姓名:{{ nameRef.value }}</p>
    <p>年龄:{{ person.age }}</p>
    <button @click="changeName">修改姓名</button>
  </div>
</template>

<script setup>
import { reactive, toRef } from 'vue';
const person = reactive({ name: '张三', age: 18 });
const nameRef = toRef(person, 'name');

const changeName = () => {
  nameRef.value = '李四';
};
</script>

简单来说就是toRef适合创建单个属性的响应式引用,这个引用是响应式的,当源对象的该属性发生变化时,通过toRef创建的引用也会同步更新。

🐟END

toReftoRefs 用于保持解构后的响应式特性,前者创建单个属性的响应式引用,后者创建整个对象所有属性的响应式引用,通过后缀s区分,有助于简化代码结构。