reactive和ref函数
在 Vue 3 的 Composition API 中,reactive 和 ref 是用于创建响应式数据的两个核心函数。
它们的核心区别在于数据类型处理方式 和使用场景。
ref 和 reactive 的对比
| 特性 | ref |
reactive |
|---|---|---|
| 适用数据类型 | 基本类型(number, string 等) |
对象或数组 |
| 返回值类型 | Ref 对象(含 .value 属性) |
Proxy 代理的响应式对象 |
| 访问值的方式 | 必须通过 .value 访问 |
直接访问属性(如 obj.key) |
| 解构响应性 | 保持响应性(无需额外处理) | 直接解构会丢失响应性,需用 toRefs |
| 使用场景 | 独立的基本类型值、需要传递的响应式变量 | 复杂对象状态管理 |
ref 的深度解析
1. 基本用法
javascript
import { ref } from 'vue';
const count = ref(0); // 定义响应式数据
console.log(count.value); // 访问值 → 0
count.value = 1; // 修改值 → 触发更新
2. 底层原理
-
ref将数据包装在一个对象中,通过.value属性实现响应式。 -
即使赋值对象,内部会自动调用
reactive处理:javascriptconst objRef = ref({ name: 'Vue' }); objRef.value.name = 'Vue 3'; // 响应式更新
3. 自动解包(模板中免 .value)
在模板中直接使用 ref 变量时,无需 .value:
vue
<template>
<div>{{ count }}</div> <!-- 自动解包,无需 count.value -->
</template>
reactive 的深度解析
1. 基本用法
javascript
import { reactive } from 'vue';
const state = reactive({
name: 'Vue',
version: 3,
});
state.name = 'Vue 3'; // 直接修改属性 → 触发更新
2. 底层原理
-
基于 ES6 的
Proxy实现,深度代理整个对象。 -
直接解构会丢失响应性 ,需用
toRefs转换:javascriptconst state = reactive({ name: 'Vue' }); const { name } = toRefs(state); // 转换为 Ref 对象 console.log(name.value); // 'Vue'(保持响应性)
3. 局限性
-
不能直接替换整个对象(会破坏响应式):
javascriptlet state = reactive({ count: 0 }); state = { count: 1 }; // ❌ 错误!失去响应性 // 正确做法:修改属性 state.count = 1; // ✅
如何选择 ref vs reactive?
1. 使用 ref 的场景
- 管理基本类型数据(如数字、字符串)。
- 需要传递响应式变量 到函数或组件时(
ref更灵活)。 - 需要明确知道某个值是响应式的(通过
.value显式操作)。
2. 使用 reactive 的场景
- 管理复杂对象或数组(如表单数据、配置对象)。
- 需要集中管理多个相关属性,保持代码组织性。
- 希望直接通过属性访问(无需
.value)。
3. 混合使用
javascript
const state = reactive({
count: ref(0), // 自动解包,state.count 仍是响应式
user: ref({ name: 'Alice' })
});
console.log(state.count); // 0(无需 .value)
常见问题解答
1. 为什么 ref 需要 .value?
ref通过对象包装实现响应式,.value是统一访问和修改值的接口。- 在模板中自动解包是为了提升开发体验。
2. 可以全部用 ref 吗?
-
可以,但处理对象时不如
reactive直观:javascriptconst obj = ref({ name: 'Vue' }); obj.value.name = 'Vue 3'; // 需要 .value -
推荐根据数据类型选择:简单类型用
ref,复杂对象用reactive。
3. reactive 如何响应式替换整个对象?
-
使用
Object.assign合并属性:javascriptconst state = reactive({ count: 0 }); Object.assign(state, { count: 1, name: 'Vue' }); // ✅ 保持响应性
示例代码对比
使用 ref:
vue
<script setup>
import { ref } from 'vue';
const count = ref(0);
const increment = () => {
count.value++;
};
</script>
<template>
<button @click="increment">{{ count }}</button>
</template>
使用 reactive:
vue
<script setup>
import { reactive } from 'vue';
const state = reactive({
count: 0,
});
const increment = () => {
state.count++;
};
</script>
<template>
<button @click="increment">{{ state.count }}</button>
</template>