Vue3 + Pinia:子组件修改 Pinia 数据,竟然影响了原始数据?

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.valuerow 指向同一块内存
  • 子组件改 rowData.value.xxx,就是在改原始 row.xxx
  • Vue 的响应式系统会让一切看起来都"流畅同步",但这不一定是你想要的!
正确做法:使用深拷贝隔离数据

这里不做第三方库的推荐,自行查找,也不建议自己手写,寻找一个好的轮子会事半功倍。这边主要介绍的是思路。

一些"取巧"的办法

1、如果你的数据只是修第一层,浅拷贝就可以解决 如:

javascript 复制代码
row = JSON.parse((JSON.stringify(row)))
Object.assign(form.value, stationStore.rowData)

2、如果要深层上面的这两个方法就无法保证数据不会被修改

欢迎大家留言探讨你们的实践经验,如有疏漏或不妥之处,欢迎在评论区指出,互相学习,共同进步!

相关推荐
鹏程十八少5 分钟前
4.Android 30分钟手写一个简单版shadow, 从零理解shadow插件化零反射插件化原理
android·前端·面试
亿元程序员12 分钟前
这款值68亿的游戏,你不实战一下吗?安排!
前端
摸鱼的春哥1 小时前
Agent教程15:认识LangChain(中),状态机思维
前端·javascript·后端
明月_清风1 小时前
告别遮挡:用 scroll-padding 实现优雅的锚点跳转
前端·javascript
明月_清风1 小时前
原生 JS 侧边栏缩放:从 DOM 监听到底层优化
前端·javascript
万少10 小时前
HarmonyOS 开发必会 5 种 Builder 详解
前端·harmonyos
橙序员小站12 小时前
Agent Skill 是什么?一文讲透 Agent Skill 的设计与实现
前端·后端
炫饭第一名15 小时前
速通Canvas指北🦮——基础入门篇
前端·javascript·程序员
王晓枫15 小时前
flutter接入三方库运行报错:Error running pod install
前端·flutter
符方昊15 小时前
React 19 对比 React 16 新特性解析
前端·react.js