直接贴上LLM的回答
什么时候使用ref?什么时候使用reactive?
这是一个非常经典的问题,很多开发者在使用组合式 API 半年后可能还在纠结。作为 CSS 大师兼 Vue 导师,我给你一个最通俗的**"选购指南"**。
1. 形象类比:单身公寓 vs. 豪华大别墅
Ref ------ "单身公寓"
ref 就像是一个单身公寓 。它主要用来住一个人(一个基础类型的值,比如字符串、数字、布尔值)。
- 特点 :因为是单间,所以你要找人的时候,必须先敲开门(加上
.value)。 - 适用人群 :
0,'hello',true, 或者一个简单的数组。
Reactive ------ "豪华大别墅"
reactive 就像是一座大别墅。里面有很多房间(属性),住着一家人(对象)。
- 特点 :你进门之后,可以直接喊"张三"、"李四"(直接访问
state.name),不需要每个房间都去敲门(不用.value)。 - 适用人群 :复杂的对象(比如用户信息、表单集合)。
2. 核心区别:到底要不要点 .value?
这是小白最容易摔跤的地方。
| 特性 | ref(0) |
reactive({ count: 0 }) |
|---|---|---|
| 访问方式 (JS) | count.value (必须加) |
state.count (直接访问) |
| 访问方式 (Template) | count (Vue 帮你自动解包) |
state.count |
| 重新赋值 | 支持 :count.value = 5 |
大忌 :不能直接 state = { ... },否则会丢失响应性 |
3. 什么时候用哪个?(实战建议)
虽然两者在很多场景下能通用,但根据经验,我建议你遵循以下**"大师准则"**:
优先使用 ref 的场景:
- 基础类型:数字、字符串、布尔值(比如显示/隐藏的开关)。
- 数组 :虽然
reactive也能存数组,但ref在处理数组替换时更稳健。 - 可能会被替换的对象 :如果你有一个用户信息对象,经常要从后端获取整个新对象并覆盖旧的,用
ref。
- 案例 :
user.value = await fetchUser()。
优先使用 reactive 的场景:
- 高度相关的成组数据 :比如一个登录表单,里面有
username、password、rememberMe。把它们打包成一个form对象更像是一个整体。 - 逻辑上的实体:比如一个"购物车"对象,里面有列表、总价、优惠券,这些属性逻辑上分不开。
4. 终极避坑指南:Reactive 的"失灵"瞬间
这是很多新手会遇到的 bug。如果你用 reactive 定义了一个对象,然后想直接给它换个"新身体",它就不再是响应式的了。
javascript
let state = reactive({ count: 0 });
// ❌ 错误做法:直接重新赋值
state = { count: 5 }; // 完了!这就像把别墅拆了盖了个平房,Vue 的监控摄像头全丢了,页面不会动了。
// ✅ 建议做法:使用 ref
const state = ref({ count: 0 });
state.value = { count: 5 }; // 没问题!换了房间里的人,摄像头还在门口盯着。
我的私人建议:
如果你是刚入门的小白 ,我建议你**"全员 ref"**。
虽然写 .value 有点烦,但它非常稳健,不会出现"数据变了页面没变"这种诡异的 bug。等你写得顺手了,再在处理复杂的表单对象时尝试 reactive。
Reactive如何重新赋值?
这是一个非常棒的观察!你的直觉很敏锐:如果不能重新赋值,那我们要这个变量干嘛呢?
其实,reactive 的**"不能重新赋值"指的是不能给这个 变量名本身换一个新的对象,但你完全可以修改对象内部的属性**。
为了让你彻底明白,我们再回到那个"别墅"的比喻:
1. 错误的改法:拆掉别墅(重新赋值变量)
当你执行 state = { count: 5 } 时,你实际上是在 JavaScript 的内存里,把 state 这个名字指向了一个全新的、普通的对象。
- 结果 :旧的那个带"监控摄像头"的
reactive对象被你扔掉了,新的这个对象只是个"平房",没有监控。Vue 失去了对它的追踪。
2. 正确的改法:装修别墅(修改内部属性)
你不能拆别墅,但你可以更换别墅里的家具 。只要你通过属性点(.)去修改,Vue 的监控摄像头(Proxy)就能捕捉到动作。
案例说明
javascript
const state = reactive({
count: 0,
user: '小白'
});
// ✅ 正确:修改属性。Vue 会看到你动了 count,并更新页面。
state.count = 5;
state.user = 'CSS大师';
// ✅ 正确:如果你一定要"批量更新"很多字段
Object.assign(state, { count: 10, user: '老手' });
3. 如果我真的有一大堆新数据要覆盖呢?
有时候,后端会返回一整个完整的新对象,你想直接替换掉 state。这时候你有两种选择:
方法 A:使用 ref(大师最推荐)
如果你预见到这个对象会被整体替换,就用 ref。
javascript
const state = ref({ count: 0 });
// 整体替换毫无压力,因为你改的是 .value
state.value = { count: 100, status: 'success' };
方法 B:使用 Object.assign
如果你坚持用 reactive,你需要把新房子的家具"搬进"旧房子里,而不是换房子。
javascript
const state = reactive({ count: 0 });
const newData = { count: 100 };
Object.assign(state, newData); // 把 newData 的内容克隆进 state
4. 总结:两者的操作手感对比
我们可以通过下面的对比表,看看当你想要改变数据时,手感有什么不同:
| 目标动作 | 使用 ref |
使用 reactive |
|---|---|---|
| 改一个数字/字符串 | count.value = 1 |
state.count = 1 |
| 改对象里的一个属性 | user.value.name = 'A' |
state.name = 'A' |
| 整个对象大替换 | user.value = { ... } (轻松) |
Object.assign(state, { ... }) (略显麻烦) |
大师建议
在 Vue3 的世界里,很多资深开发者现在倾向于 "几乎全部使用 ref"。
原因很简单:ref 虽然多写一个 .value,但它像是一张"万能牌",不管是简单数字还是复杂对象,不管是改属性还是换整体,它都表现得非常稳健,不会让你在"重新赋值"上栽跟头。