在 Vue3 的组合式 API (Composition API)中,ref 和 reactive 是用于创建响应式数据的两个核心函数。尽管二者都用于实现响应式数据,但在使用方式和适用场景上存在一些区别。
1. 基本概念
1.1 ref
用途:用于定义 基本类型 (如字符串、数字、布尔值)和 简单对象 的响应式数据。
返回值:一个包含 value 属性的 响应式对象。
特点:
1、对于基本类型,ref 会将其包装在一个带有 .value 属性的对象中。
2、对于对象类型,ref 也会对其内部属性进行深度响应式转换。
1.2 reactive
用途:用于定义 复杂对象(如对象、数组)的响应式数据。
返回值:原始对象的 响应式代理 proxy。
特点:
1、对传入的对象进行 深度响应式 转换,即对象内部所有嵌套的属性也都是响应式的。
2、返回的对象看起来与原始对象相同,不用通过 .value 访问属性。
2. 具体描述
2.1 深度响应性
1、ref
1)对于 基本类型,ref 只包装值本身。
2)对于 对象类型 ,ref 会对对象内部进行 深度响应式 处理,与 reactive 类似。
示例:
javascript
const obj = ref({
a: 1,
b: {
c: 2
}
});
obj.value.b.c = 3; // 响应式更新
2、reactive
1)总是对传入的对象进行 深度响应式 处理。
示例:
javascript
const obj = reactive({
a: 1,
b: {
c: 2
}
});
obj.b.c = 3; // 响应式更新
注意 :在 Vue 3 中,reactive 和 ref 对对象类型的数据都会进行深度响应式处理。
2.2 解构问题
解构赋值时的响应性丢失:
1、reactive 对象在解构时会丢失响应性。
javascript
<template>
<div>state.count:{{ state.count }}</div>
</template>
<script setup>
import { reactive } from 'vue';
const state = reactive({
count: 0
});
let { count } = state;
console.log('count:', count);
count++; // 不是响应式的,界面不会更新
console.log('count:', count);
</script>
解决方案 :使用 toRefs将 reactive对象转换为响应式引用。
javascript
import { reactive, toRefs } from 'vue';
const state = reactive({
count: 0
});
const { count } = toRefs(state);
console.log('count:', count);
count.value++; // 响应式更新,界面会更新
console.log('count:', count);
2、ref 在解构时同样也会丢失响应性,因为解构操作提取的是当前值,而不是保持对 ref 对象的响应式引用。
javascript
import { ref } from 'vue';
const countRef = ref(0);
// 解构 ref
const { value: countValue } = countRef;
// 修改 ref 的值
countRef.value++;
console.log('countValue:', countValue); // 输出 0,因为 countValue 已经解构出来,并且不再响应
// 直接使用 ref 的 .value 属性
console.log('countRef.value:', countRef.value); // 输出 1,因为 countRef 仍然是响应式的
2.3 响应式转换的辨识
1、ref 创建的响应式对象有一个 Ref 标记,可以通过 isRef 进行判断。
javascript
import { ref, isRef } from 'vue';
const count = ref(0);
console.log(isRef(count)); // true
2、reactive 创建的响应式对象可以通过 isReactive 进行判断。
javascript
import { reactive, isReactive } from 'vue';
const state = reactive({ count: 0 });
console.log(isReactive(state)); // true
3. 何时使用
1、ref
当需要创建一个简单的、可响应的基本类型数据(如字符串、数字、布尔值)时。
当需要从 reactive 对象中解构某个属性,并保持响应性时,可以使用 toRef 或 toRefs。
2、reactive
当需要创建包含多个属性的对象或数组,并希望所有嵌套属性都具有响应性时。
当需要在模板中频繁访问对象的多个属性时,reactive 会比多个 ref 更简洁。