完整教程:Vue3 响应式 API:ref 和 reactive 怎么选?用 1 个例子讲透

上一篇我们对比了 Vue2 和 Vue3 的 API 写法,但有个关键问题没说透:为什么有时候我们在 Vue3 里改了变量,页面却不更新?比如这样写:

<script setup>
let count = 0;
function addCount() {
  count += 1; // 改了变量,但页面不更新!
}
</script>

这不是 BUG,而是因为 Vue3 需要用 “响应式 API”(ref/reactive)包裹变量,才能让页面 “感知” 到变量变化。这篇就用最直白的案例,讲清 ref 和 reactive 的用法、区别和选择逻辑,从此告别 “变量改了页面不动” 的坑。

先搞懂:什么是 “响应式”?​

用大白话讲:变量变了,页面自动跟着变,不用手动刷新,这就是响应式。​

比如我们要做一个 “计数器”,点击按钮让 count 从 0 变成 1,页面能立刻显示 1—— 要实现这个效果,就必须用 ref 或 reactive 把 count 变成 “响应式变量”。​

Vue3 的响应式原理和 Vue2 不同(Vue2 用Object.defineProperty,Vue3 用Proxy),但不用深扒原理,记住 “用对 API” 就行,重点看下面的案例。​

第一部分:ref—— 适合给 “基础类型” 做响应式​

基础类型指的是:数字(number)、字符串(string)、布尔值(boolean),比如 count=0、name="张三"、isShow=true。​

1.1 ref 的用法:3 步搞定​
步骤 1:引入 ref(必须!)​

Vue3 的响应式 API 需要手动引入,在<script setup>开头加一行:

<script setup>
// 从vue里引入ref
import { ref } from "vue";
</script>
步骤 2:用 ref 包裹变量,定义响应式数据​

把普通变量用ref()包起来,比如定义响应式的 count:

<script setup>
import { ref } from "vue";
// 用ref包裹基础类型,变成响应式变量
const count = ref(0); // 初始值0
</script>
步骤 3:修改值要加.value,模板里不用​
  • JS 里修改:ref 包裹的变量,在<script>里改值必须加.value(这是 ref 的核心特点,也是新手常忘的坑)​
  • 模板里使用:在<template>里直接用变量名,不用加.value​

完整计数器案例:


<script setup>
import { ref } from "vue";
const count = ref(0); // 响应式变量
function addCount() {
  // JS里改值必须加.value!
  count.value += 1;
}
</script>

保存后点击按钮,页面会实时更新计数 —— 这就是响应式的效果!​

1.2 ref 也能包裹对象(但不推荐)​

虽然 ref 主要用在基础类型,但也能包裹对象(比如用户信息),只是修改属性时同样要加.value:

<script setup>
import { ref } from "vue";
// ref包裹对象
const user = ref({
  name: "张三",
  age: 20
});
function changeUser() {
  // 改属性:user.value.属性名
  user.value.name = "李四";
  user.value.age = 22;
}
</script>

但这样写有点麻烦(要多写.value),所以对象类型更推荐用下面的 reactive。​

第二部分:reactive—— 适合给 “复杂类型” 做响应式​

复杂类型指的是:对象(object)、数组(array),比如 user={name:""}、list=[1,2,3]—— 这些包含多个子属性 / 元素的数据,用 reactive 更顺手。​

2.1 reactive 的用法:3 步搞定​
步骤 1:引入 reactive(必须!)​

和 ref 一样,先从 vue 里引入:

<script setup>
import { reactive } from "vue";
</script>
步骤 2:用 reactive 包裹对象 / 数组,定义响应式数据​

比如定义一个 “用户信息” 对象,包含 name 和 age 两个属性:

<script setup>
import { reactive } from "vue";
// 用reactive包裹对象,变成响应式数据
const user = reactive({
  name: "张三",
  age: 20
});
</script>
步骤 3:修改值不用加.value,直接改属性​
  • JS 里修改:reactive 包裹的对象,直接通过 “对象。属性” 修改,不用加.value​
  • 模板里使用:和 ref 一样,直接用 “对象。属性”​

完整用户信息修改案例:


<script setup>
import { reactive } from "vue";
const user = reactive({
  name: "张三",
  age: 20
});
function changeUser() {
  // 直接改属性,不用加.value,比ref更简洁
  user.name = "李四";
  user.age = 22;
}
</script>

点击按钮,页面会立刻更新用户信息 —— 对比 ref 包裹对象的写法,reactive 少了.value,更清爽。​

2.2 reactive 的避坑点:不能直接 “重新赋值整个对象”​

这是 reactive 最容易踩的坑!如果直接给 reactive 对象赋值,会丢失响应式,比如这样写:

<script setup>
import { reactive } from "vue";
const user = reactive({ name: "张三", age: 20 });
function changeUser() {
  // 错误写法:直接赋值整个对象,响应式会丢失!
  user = { name: "李四", age: 22 };
  // 改完后页面不更新,因为user变成了普通对象
}
</script>

正确写法:要么改属性(像之前那样),要么用Object.assign合并对象:

function changeUser() {
  // 正确写法1:改单个属性
  user.name = "李四";
  user.age = 22;
  // 正确写法2:用Object.assign合并(适合多属性修改)
  Object.assign(user, {
    name: "李四",
    age: 22
  });
}

第三部分:关键对比 ——ref 和 reactive 怎么选?​

用 “用户信息 + 计数器” 的综合案例,分别用 ref 和 reactive 实现,直观对比两者的差异:​

案例需求:​

  1. 显示用户姓名、年龄​
  2. 显示计数器(初始 0)​
  3. 一个按钮:修改用户信息 + 计数器加 1​

用 ref 实现(基础类型 + 对象):


<script setup>
import { ref } from "vue";
// 基础类型用ref
const count = ref(0);
// 对象也用ref(但要多写.value)
const user = ref({ name: "张三", age: 20 });
function handleClick() {
  count.value += 1; // 加.value
  user.value.name = "李四"; // 加.value
  user.value.age = 22; // 加.value
}
</script>

用 reactive 实现(对象包裹所有数据):


<script setup>
import { reactive } from "vue";
// 用一个reactive对象包裹所有数据(count+user)
const data = reactive({
  count: 0,
  user: { name: "张三", age: 20 }
});
function handleClick() {
  data.count += 1; // 不用加.value
  data.user.name = "李四"; // 不用加.value
  data.user.age = 22; // 不用加.value
}
</script>
选择口诀(10 秒判断):​
  1. 基础类型(number/string/boolean):优先用 ref(reactive 不支持单独的基础类型)​
  2. 复杂类型(object/array):优先用 reactive(比 ref 少写.value,更简洁)​
  3. 不确定或混合类型:用 ref 包裹对象(虽然麻烦点,但不容易丢响应式)​
  4. 追求代码统一:全用 ref(比如项目里既有基础类型又有对象,全用 ref 不用记两种规则)

第四部分:实战避坑总结​

  1. ref 的.value只在 JS 里加:模板里不用加,加了会报错​
  2. reactive 不能直接赋值整个对象:只能改属性或用Object.assign​
  3. 数组用 reactive 更方便:比如const list = reactive([1,2,3]),修改时直接list.push(4),不用加.value​
  4. 解构 reactive 会丢失响应式:比如const { name } = user,改name页面不更新,解决方法:用toRefs(下一篇讲)​

总结:这篇你学会了什么?​

  1. 响应式的核心:变量变,页面自动变,需要用 ref/reactive 包裹​
  2. ref 用法:基础类型优先,JS 改值加.value,模板不用​
  3. reactive 用法:复杂类型优先,直接改属性,不用加.value​
  4. 选择口诀:基础用 ref,对象用 reactive,不确定全用 ref​

下一篇我们会讲 “解构响应式数据” 的问题 —— 比如用const { name } = user后改 name 页面不更新怎么办?还有toRefs和toRef的用法,彻底解决响应式数据的 “灵活使用” 问题!如果这篇的案例你有疑问,或者想测试其他场景,欢迎在评论区留言~

posted @ 2025-11-14 16:09  gccbuaa  阅读(78)  评论(0)    收藏  举报