vue3基础:ref() 、reactive()、toRefs()

89 阅读3分钟

ref()

创建响应式数据:

ref() 可以用来创建任何类型的响应式数据,不仅限于基本类型,还可以是对象、数组、Map等复杂数据结构。

####需要直接访问值:

返回的 ref 对象只有一个指向其内部值的属性 .value,通过它来读取或修改实际的值。

const name = ref('Alice’)
console.log(name.value) // Alice

注意:name变量不具有响应式,name.value才具有响应式。

模板自动解包:

template中使用 ref 时,我们不需要附加 .value。当在template中使用时,ref 会自动解包。

<template>
  <div>{{ count }}</div>
</template>

<script setup>
import { ref } from 'vue'

const count = ref(0)

console.log(count.value) // 0
</script>

深度响应式:

ref()将使其值具有深度响应式,即使改变嵌套对象或数组时,变化也会被检测到。

import { ref } from 'vue'

const obj = ref({
  nested: { count: 0 },
  arr: ['foo', 'bar']
})

function mutateDeeply() {
  // 以下都会按照期望工作
  obj.value.nested.count++
  obj.value.arr.push('baz')
}

reactive()

创建响应式对象:

reactive() :接收一个普通对象作为参数,返回对象的响应式代理。

const state = reactive({ count: 0, name: 'Alice' })

state 对象及其所有嵌套的属性,(如 state.countstate.name)都具有响应式。

不能用于原始类型:

它只能用于对象类型 (对象、数组和如 MapSet 这样的集合类型)。它不能持有如 stringnumberboolean 这样的原始类型。

深度响应式:

reactive() 不仅使顶层对象本身响应式,还会递归地将对象内部的属性(无论多么深层次)以及数组的元素转变为响应式。

不能替换整个对象:

由于 Vue 的响应式跟踪是通过属性访问实现的,因此我们必须始终保持对响应式对象的相同引用。

let state = reactive({name: 'Alice' })

// 上面的 ({ count: 0 }) 引用将不再被追踪
// (响应性连接已丢失!)
state = reactive({ count: 1 }) 

不能替换整个对象,可以使用 Object.assing() 合并对象。

import { ref, reactive } from 'vue'

const user = reactive({ name: 'Alice' })
Object.assign(user, { name: 'Tony', age: 18 })

console.log(user.name, user.age) // Tony 18

解构赋值丢失响应式:

当我们将响应式对象的原始类型属性解构为本地变量时,或者将该属性传递给函数时,我们将丢失响应性连接:

const state = reactive({ count: 0 })

// 当解构时,count 已经与 state.count 断开连接
let { count } = state
// 不会影响原始的 state
count++

// 该函数接收到的是一个普通的数字
// 并且无法追踪 state.count 的变化

应用场景:

比如表单对象、状态对象。

toRefs()

属性转换:

将一个响应式对象转换为一个普通对象,这个普通对象的每个属性都是指向源对象相应属性的 ref。虽然 toRefs() 返回的对象是普通对象,但它内部的属性实际上是 ref。因此,在访问或修改属性值时,需要使用 .value

方便解构赋值:

由于返回对象的属性已经是 ref,可以直接进行解构赋值,且在解构后仍能保持响应性。这解决了响应式丢失问题。

示例代码:

import { reactive, toRefs } from 'vue';

// 创建一个响应式对象
const state = reactive({
  name: 'Alice',
  age: 25,
  address: {
    city: '北京'
  }
});

// 使用 toRefs 转换为独立的 ref
const stateAsRefs = toRefs(state);

// 现在可以解构赋值并保持响应性
const { name, age, address } = stateAsRefs;
// 改变 ref 值会触发视图更新
name.value = 'Bob';
address.value.city = '广州';