ref() 和 reactive()响应性 浅解

发布于:2025-02-21 ⋅ 阅读:(18) ⋅ 点赞:(0)

在 Vue 3 中,ref()reactive() 都是用于响应式数据管理的 API,它们的主要作用是让数据具有响应性,使 Vue 组件在数据变化时能够自动更新视图。它们有一定的关联,但用法和适用场景有所不同。


1. ref()reactive() 的区别

对比点 ref() reactive()
适用场景 适用于基本类型(Number、String、Boolean)和对象 适用于对象(Object、Array、Map、Set等)
是否需要 .value 需要:count.value 不需要,直接访问属性:state.count
是否可以解构 不能直接解构,会丢失响应性 不能直接解构,会丢失响应性
适用于数组/对象 适用于任意类型的数据,但访问对象时需要 .value 适用于复杂的对象和数组
底层实现 ref 内部使用 reactive 处理对象 使用 Proxy 代理对象,实现响应性

2. 解构 详解

情况 示例 是否丢失响应性? 原因 解决方案
ref(基本类型) const count = ref(0);
count.value++
不会 count 本身是 ref,Vue 追踪 count.value 直接 count.value++
ref(对象类型) 并直接修改 .value const user = ref({ name: 'Alice' });
user.value.name = 'Bob';
不会 user.value 仍然是响应式对象 直接修改 user.value.name
解构 ref(对象).value const { name } = user.value;
name = 'Bob';
会丢失 name 是普通变量,Vue 不再追踪 使用 toRefs(user.value)
解构 reactive(对象) const user = reactive({ name: 'Alice' });
const { name } = user;
name = 'Bob';
不会 reactive 生成的是 Proxy,解构后仍然保持响应性 直接解构 const { name } = user;
reactive 对象包含 ref() const user = reactive({ name: ref('Alice') });
user.name = 'Bob';
不会 user.nameref,Vue 能追踪 user.name.value 访问 user.name.value
reactive 里存 ref 并解构 const user = reactive({ name: ref('Alice') });
const { name } = user;
name = 'Bob';
会丢失 name 变成 ref,但解构后 Vue 不会追踪 name.value 改为 toRef(user, 'name')
解构 reactive() 并使用 toRefs() const user = reactive({ name: 'Alice' });
const { name } = toRefs(user);
不会 toRefs()user.name 转换为 ref,仍然响应式 继续 name.value = 'Bob'

2.1. 什么是解构

解构是 JavaScript用于从对象或数组中提取值的语法,允许你将数据拆分并存储到独立的变量中。
看个例子,一眼便知

<script setup>
import { reactive } from 'vue';

const state = reactive({
  count: 0,
  message: 'Hello'
});

// ❌ 直接解构(会丢失响应性)
let { count, message } = state;

const increment = () => {
  count++; // ❌ 这里不会触发视图更新
};
</script>

<template>
  <p>{{ count }}</p> <!-- 不会更新 -->
  <button @click="increment">+</button>
</template>

2.2. 解构避免丢失响应性的办法

在 Vue 3 中,reactive() 返回的对象在解构后会丢失响应性,这是因为 reactive() 使用的是 Proxy,而解构时只会拷贝属性值,而不会保留 Proxy 代理能力。

2.2.1. 解决方案:toRefs() 保持响应性
  • toRefs(state) state 的每个属性变成 ref(),这样解构出来的 countmessage 就是 ref,修改 .value 仍然会触发 Vue 的响应式系统。

toRefs() 用于将 reactive 对象的属性转换成 ref,这样解构后仍然保持响应性:

<script setup>
import { reactive, toRefs } from 'vue';

const state = reactive({
  count: 0,
  message: 'Hello'
});

// ✅ 使用 toRefs() 让解构后的变量仍保持响应性
const { count, message } = toRefs(state);

const increment = () => {
  count.value++; // ✅ 这里会触发视图更新
};
</script>

<template>
  <p>{{ count }}</p> <!-- 视图会更新 -->
  <button @click="increment">+</button>
</template>
2.2.2. 解决方案: toRef()保持响应性

如果你只想让某个属性保持响应性,而不是整个 state,可以使用 toRef()

<script setup>
import { reactive, toRef } from 'vue';

const state = reactive({
  count: 0,
  message: 'Hello'
});

// ✅ 只把 count 变成 ref
const count = toRef(state, 'count');

const increment = () => {
  count.value++; // ✅ 仍然是响应式的
};
</script>

<template>
  <p>{{ count }}</p>
  <button @click="increment">+</button>
</template>

3. 最佳实践

  • 基本类型ref()
  • 对象reactive()
  • 解构 reactive ➝ 用 toRefs()
  • 解构 ref(对象).value不能直接解构,必须用 toRefs()

网站公告

今日签到

点亮在社区的每一天
去签到