ref()与reactive()有什么区别?
原文地址:Ref() vs Reactive() in Vue 3 — what’s the right choice?,2022.01.29,by Bartosz Salwiczek
Vue Composition API 提供了两种创建响应式状态的方式:ref() 和 reactive()。你可能会好奇,在开发中到底该选哪一个?甚至是两者都用?我们需要更深入一些,理解它们的区别、适用场景,并做出合理选择。
以下是对你提供的文章内容的全面润色和改写,在不改变原意的前提下,使语言更流畅、更具可读性,适合用于博客或技术文档中发布:
快速了解:ref 与 reactive 的本质
无论是 ref() 还是 reactive(),它们的核心作用是让 Vue 能够追踪状态的变化,一旦变量更新,Vue 会自动重新渲染使用该变量的部分。
看下面这个例子,点击按钮后 personRef 和 personReactive 的 name 都会变成 “Amy”,而普通对象 person 则不会触发视图更新。
<template>
{{ person.name }} <!-- 不会变 -->
{{ personRef.name }} <!-- 会变为 Amy -->
{{ personReactive.name }} <!-- 会变为 Amy -->
<button @click="changeName('Amy')">Change Name</button>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
const person = { name: 'John' }
const personRef = ref({ name: 'John' })
const personReactive = reactive({ name: 'John' })
const changeName = (name: string) => {
person.name = name
personRef.value.name = name
personReactive.name = name
}
</script>
简而言之:ref() 和 reactive() 都是为了让变量具备响应性,以响应视图的变化。
核心区别
1. 支持的数据类型不同
ref():支持任意类型,包括基本类型(如字符串、数字、布尔值)和对象。reactive():只能接受对象。
// 无效:reactive 不支持原始类型
const x = reactive(true)
// 有效
const y = ref(true)
两者都可以包装对象:
const obj1 = ref({ name: 'John' })
const obj2 = reactive({ name: 'John' })
2. ref 有 .value 属性,reactive 没有
使用 ref() 时,需要通过 .value 获取或修改数据;而 reactive() 则可以直接访问属性。
// reactive 示例
const person = reactive({ name: 'John' })
person.name = 'Amy'
// ref 示例
const personRef = ref({ name: 'John' })
personRef.value.name = 'Amy'
🔎 小提示:在模板中使用 ref 时,不需要写
.value,Vue 会自动解包。
3. ref 支持整个值替换,reactive 不支持
// reactive 无法整体替换对象
let x = reactive({ name: 'John' })
x = reactive({ todo: true }) // Vue 不会追踪新对象的变动
// ref 可以直接替换整个值
const y = ref({ name: 'John' })
y.value = { todo: true } // 正常响应
为何需要同时存在两者?
看上去 reactive() 像是功能更少的 ref(),那为什么还要用它呢?其实,Vue 团队有其考虑。
我们可以看看 Vue 源码中 ref() 的实现:
class RefImpl<T> {
private _value: T
private _rawValue: T
...
constructor(value: T, isShallow: boolean) {
this._rawValue = isShallow ? value : toRaw(value)
this._value = isShallow ? value : toReactive(value)
}
}
你没看错,ref() 本质上就是把数据转换成 reactive() 的包装,也就是说:
const myRef = reactive({ value: "I'm ref!" })
myRef.value = 'Changed'
所以可以理解为:ref 是基于 reactive 实现的封装。
reactive 的最佳使用场景
优点:避免频繁使用 .value
使用多个 ref 时,需要不断地访问 .value,看起来有些冗余。reactive() 则更接近 Vue 2 中的 data() 结构,更加直观。
例如:
// 使用 reactive 管理组件状态
const state = reactive({
user: { name: 'John' },
isLoading: false,
hasError: false
})
相比之下,如果使用 ref():
const user = ref({ name: 'John' })
const isLoading = ref(false)
const hasError = ref(false)
后者会造成变量和模板中频繁使用 .value,并且不如集中式的管理清晰。
性能方面的区别
使用多个 ref() 变量会导致整个对象在某个属性变动时被整体更新;而 reactive() 能对每个属性进行追踪,只更新有变动的部分,这样更高效。
总结:如何选择?
| 使用场景 | 推荐使用 |
|---|---|
| 管理多个独立的值 | ref() |
| 管理单个状态对象 | reactive() |
| 需要响应式的原始类型 | ref() |
不想频繁写 .value |
reactive() |
| 需要整体替换状态对象 | ref() |
个人观点
虽然 ref() 和 reactive() 在功能上有重合,但它们各自适用于不同的开发习惯:
- 如果你更喜欢统一风格、使用频率更广,推荐优先使用 **
ref()**。 - 如果你希望更接近 Vue 2 的写法、状态集中管理,或者避免
.value的使用,那么reactive()是更好的选择。
我个人倾向默认使用
ref(),甚至很多情况下用了reactive()后一些情况还需要toRef()把对象解构出来,因为.value可以作为“响应式标识”,让代码可读性更强。
你也可以理解为:
ref():适合单值响应(原始值/复杂对象)reactive():适合状态容器(多个字段统一管理)
欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1701220998@qq.com