在 Vue 3 中,reactive
和 ref
是两种常用的响应式数据声明方式。但在实际开发中,我们常会遇到一个问题:明明对象的属性值发生变化了,界面却没有更新。
本文将通过实际代码问题来分析原因,并给出最佳实践。
一、常见问题示例
以下代码使用了 reactive
创建响应式对象:
const dataObj = reactive({
data: [],
total: 0
})
http.post('/api/trade/bargain_detail_list', params).then(res => {
const { data } = res
dataObj.data = data
dataObj.total = data.length
})
乍看之下没问题,但你会发现页面没有更新数据。为什么?
二、问题分析
reactive
是基于 Proxy
实现的深层响应式代理,它能追踪对象属性的读取与设置。然而:
如果组件并没有显式使用某个属性,Vue 就不会建立对它的响应式依赖。
例如组件内部只读取了一次 dataObj
,而不是 dataObj.data
,那即使你改了 dataObj.data
,也不会触发更新。
而使用 ref
就不会出现这种问题:
const dataObj = ref({
data: [],
total: 0
})
// 替换整个对象,页面响应更新
dataObj.value = {
...dataObj.value,
data: res.data,
total: res.data.length
}
这种方式 Vue 能检测到整个对象变化,依赖会被更新。
三、推荐解决方案
方案 1:使用 ref 包裹对象
const dataObj = ref({
data: [],
total: 0
})
dataObj.value.data = res.data
dataObj.value.total = res.data.length
方案 2:使用 reactive,但操作内部属性需谨慎
避免整体替换属性,推荐使用数组变更方法:
dataObj.data.splice(0, dataObj.data.length, ...res.data)
这样可以保留数组的响应式引用,触发组件更新。
四、何时用 reactive?何时用 ref?
场景 | 推荐 |
---|---|
定义一个简单的基本类型(如 string, number) | ref |
定义一个对象但需要替换整体数据 | ref |
定义一个结构稳定的复杂对象,并不替换它本身 | reactive |
五、总结
reactive
是深层响应,但不能整体替换属性对象,否则可能不更新。ref
包裹对象后使用.value
可整体替换并触发响应。- 推荐在异步数据赋值中使用
ref
+ 替换整个对象。
掌握好这两者的差异与用法,能让你的 Vue 3 项目响应更流畅,逻辑更清晰。