1、业务场景
在组件通信中,我们经常遇到这样的需求:
- 表格中的每一行都有一个"编辑"按钮
- 点击按钮,打开弹窗,展示该行数据用于编辑
- 修改完成后提交,或取消编辑
初始实现代码
1️、父组件中使用 Pinia 设置当前行数据
javascript
// store/station.ts
export const useStationStore = defineStore('station', () => {
const rowData = ref<RowType>({
name: '',
id: '',
// ...
})
const setRowData = (row: RowType) => {
rowData.value = row // 注意这里
}
return { rowData, setRowData }
})
2、父组件中点击编辑按钮
ini
const edit = (row: RowType) => {
stationStore.setRowData(row)
visible.value = true
}
3、子组件中直接使用 rowData
arduino
const { rowData } = storeToRefs(useStationStore())
// 在表单中双向绑定使用
<el-input v-model="rowData.name" />
好像到这里一切都没有问题,当我们点击编辑、修改数据的时候,就会发现 表格中的原始数据被修改了,我们分析一下原因
引用传递 + 响应式副作用
ini
rowData.value = row
这里做的是引用赋值,也就是说:
rowData.value
和row
指向同一块内存- 子组件改
rowData.value.xxx
,就是在改原始row.xxx
- Vue 的响应式系统会让一切看起来都"流畅同步",但这不一定是你想要的!
正确做法:使用深拷贝隔离数据
这里不做第三方库的推荐,自行查找,也不建议自己手写,寻找一个好的轮子会事半功倍。这边主要介绍的是思路。
一些"取巧"的办法
1、如果你的数据只是修第一层,浅拷贝就可以解决 如:
javascript
row = JSON.parse((JSON.stringify(row)))
Object.assign(form.value, stationStore.rowData)
2、如果要深层上面的这两个方法就无法保证数据不会被修改
欢迎大家留言探讨你们的实践经验,如有疏漏或不妥之处,欢迎在评论区指出,互相学习,共同进步!