Vue 3 中修改响应式对象的正确姿势——Object.assign 解决表格数据更新不刷新问题
·
一、问题场景:点击“查看”解密收件信息
📄 表格代码示例
<el-table :data="tableData">
<el-table-column label="收件信息" width="280">
<template #default="scope">
<div>
<!-- 显示收件人姓名和电话 -->
<span>{{ scope.row.receiverName }} {{ scope.row.receiverPhone }}</span>
<!-- 查看按钮:解密信息 -->
<el-button size="small" type="text" @click="handleWatch(scope.row)">查看</el-button>
<el-button size="small" type="text" @click="handleUpdate(scope.row)">修改</el-button>
</div>
<!-- 显示省市区和详细地址 -->
<div>
<span>{{ scope.row.receiverProvince }}{{ scope.row.receiverCity }}{{ scope.row.receiverDistrict }}</span>
<span>{{ scope.row.receiverDetailAddress }}</span>
</div>
</template>
</el-table-column>
</el-table>
❌ 错误写法:直接替换 row
async function handleWatch(row) {
const res = await getDecryptReceiverInfo(row.id)
// ⚠️ 问题:重新赋值,导致响应式失效
row = {
receiverName: res.data.receiverName,
receiverPhone: res.data.receiverPhone,
receiverDetailAddress: res.data.receiverAddress,
...row
}
// 结果:数据变了,但页面没刷新!
}
二、问题根源:Vue 响应式系统无法监听对象替换
🔍 核心原理
Vue 的响应式系统监听的是对象属性的变化,而不是变量引用的替换。
row = { ... }是变量重新赋值,row指向了一个新对象。- 原始数据(如
tableData中的项)仍然指向旧对象。 - Vue 无法感知原始对象被“替换”,因此不会触发视图更新。
📌 关键区别:
- ✅ 修改属性:
row.name = '张三'→ 触发更新- ❌ 替换对象:
row = { ...row, name: '张三' }→ 不触发更新
三、正确方案:使用 Object.assign 修改原对象
✅ 推荐写法
/** 查看解密的收件信息 */
async function handleWatch(row) {
const res = await getDecryptReceiverInfo(row.id)
Object.assign(row, res.data)
}
✅ 为什么 Object.assign 有效?
row仍然是同一个对象(引用未变)。Object.assign是对原对象的属性赋值操作。- Vue 的响应式系统能监听到这些
set操作,从而触发视图更新。
四、Vue 3 的优势:无需担心新增属性
Vue 3 使用 Proxy 实现响应式,相比 Vue 2 有巨大提升:
| 能力 | Vue 2 | Vue 3 |
|---|---|---|
| 监听属性新增 | ❌ 需 this.$set |
✅ 自动支持 |
| 监听属性删除 | ❌ 需 this.$delete |
✅ 自动支持 |
| 监听数组索引修改 | ❌ 需特殊处理 | ✅ 自动支持 |
🎉 这意味着在 Vue 3 中:
- 即使
receiverName字段之前不存在,Object.assign添加它也会是响应式的。- 你无需使用
ref或reactive包装每一行数据,直接修改即可。
五、其他可行方案对比
| 方法 | 代码示例 | 适用场景 |
|---|---|---|
Object.assign |
Object.assign(row, data) |
✅ 推荐,批量更新 |
| 直接赋值 | row.name = 'xxx' |
单字段更新 |
| 解构赋值(错误) | row = { ...row, name: 'xxx' } |
❌ 不触发更新 |
Object.keys + 循环 |
Object.keys(data).forEach(k => row[k] = data[k]) |
复杂逻辑时备用 |
六、最佳实践总结
✅ 正确做法
- ✅ 修改对象属性,而不是替换对象。
- ✅ 使用
Object.assign批量更新字段。 - ✅ Vue 3 中无需担心新增属性的响应式问题。
❌ 错误做法
- ❌
row = { ...row, key: value } - ❌ 在 Vue 3 中过度使用
ref包装每个字段。
七、结语
“不要替换对象,要修改属性” —— 这是 Vue 响应式开发的核心心法。
通过 Object.assign,我们不仅能解决“数据更新但视图不刷新”的常见问题,还能写出更简洁、更易维护的代码。尤其是在 Vue 3 的加持下,响应式系统更加智能和强大,开发者可以更专注于业务逻辑,而不是响应式细节。
下次遇到类似问题,记得先检查:你是不是不小心替换了对象引用?
更多推荐



所有评论(0)