细讲 Vue 3 中 ref 和 reactive 的区别
1️⃣ reactive 与 ref 的基本概念
reactive
-
用于 创建响应式对象(通常是对象或数组)。
-
会 递归地把对象的每个属性都变成响应式。
-
常用于对象、数组、Map、Set 等。
import { reactive } from 'vue'
const state = reactive({
count: 0,
info: { name: 'Vue' }
})
// 使用
state.count++ // count 改变,视图会更新
state.info.name = 'Vue3' // info.name 改变,视图会更新
特点:
-
对象和数组适合用
reactive -
直接访问属性即可,无需
.value
ref
-
用于 创建一个包含单一值的响应式引用。
-
ref返回的是一个 对象,有一个.value属性保存实际的值。 -
可以用来保存 基本类型数据(string, number, boolean),也可以保存对象、数组。
import { ref } from 'vue'
const count = ref(0)
// 使用
count.value++ // 必须用 .value,视图才会更新
// ref 包含对象
const info = ref({ name: 'Vue' })
info.value.name = 'Vue3' // 对象内部修改同样响应式
特点:
-
基本类型一定要用
ref才能响应式。 -
访问值需要
.value。 -
组合式 API中常用
ref来单独管理简单数据。
2️⃣ 为什么 ref 要用 .value?
核心原因:
-
ref本身是一个 对象包装器,它内部包含了一个响应式引用。 -
Vue 通过这个对象来 跟踪依赖,实现响应式更新。
-
如果直接操作基本类型而不通过
.value,Vue 无法劫持变化。
拓展:什么是“劫持变化”?
在 Vue3 里,响应式的核心就是 数据劫持。
-
Vue 会在你访问/修改数据的时候 拦截操作,收集依赖,通知组件更新。
-
这个拦截主要依靠 Proxy(对对象) 和 getter/setter(对 ref 的
.value)来实现。 -
JavaScript 的基本类型(number、string、boolean、null、undefined、symbol、bigint)是 值类型,不是对象。
-
它们没有 getter/setter,可以直接赋值。
-
所以 Vue 没法直接拦截
let count = 0这种变化。
举例:
const count = ref(0)
// Vue 内部类似这样
// count = { value: 0, __v_isRef: true }
所以访问或修改必须写成:
count.value = 5
console.log(count.value)
如果你写成 count = 5:
-
只是给变量
count重新赋值,并不会触发 Vue 的响应式更新。
提示:如果是对象类型,访问对象的属性不需要
.value,但访问 ref 本身仍需要.value。
3️⃣ reactive 与 ref 的对比总结
| 特性 | reactive | ref |
|---|---|---|
| 用途 | 对象/数组 | 基本类型或对象引用 |
| 返回值 | 响应式对象本身 | 带 .value 的对象 |
| 修改方式 | state.count = 1 | count.value = 1,info.value.name='青年' |
| 嵌套属性 | 自动递归响应 | 对象需通过 .value 访问属性 |
| 适用场景 | 状态对象/复杂数据 | 单一数据或简单引用 |
4️⃣ 小技巧
-
如果你想把基本类型的
ref当作普通变量使用,可以用 解构 +toRefs或unref:
import { ref, unref } from 'vue'
const count = ref(0)
console.log(unref(count)) // 输出 0
-
Vue 模板中可以直接使用 ref,无需
.value:
<template>
<p>{{ count }}</p>
</template>
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
💡 总结:
-
reactive用于对象/数组,访问属性直接用。 -
ref用于基本类型或引用,访问或修改必须.value。 -
Vue 内部通过
.value对 ref 进行响应式劫持。
更多推荐
所有评论(0)