markdown
# 踩坑笔记:Vue 动态 Key 导致组件无限重置与 API 重复提交
## 1. 问题描述
在父组件 (`SampleDetail.vue`) 引用子组件 (`AirStyleTable.vue`) 时,页面初始化或进行任何交互(如切换下拉框、输入文字)时,接口频繁报错:
> **Error: 数据正在处理,请勿重复提交**
同时观察 Network 面板,发现同一个 API (`getDeviceList`) 在极短时间内被连续调用了多次。
## 2. 问题代码
**SampleDetail.vue (父组件)**
```html
<!-- 错误写法:使用时间戳作为 key -->
<AirStyleTable
:oldData="form"
:key="new Date().getTime()"
ref="airStyleTable"
></AirStyleTable>
AirStyleTable.vue (子组件)
javascript
created() {
// 组件初始化时调用接口
this.getDeviceList();
}
3. 原因深度分析
3.1 核心机制冲突
- Vue 的更新机制 :当父组件的响应式数据(如
form.province或form本身)发生变化时,父组件的render函数会重新执行。 - 动态 Key 的陷阱 :
new Date().getTime()是一个非纯函数 。每次render执行时,它都会返回一个全新的时间戳(例如从...001变成...005)。 - Diff 算法判决 :Vue 对比新旧虚拟 DOM 时,发现组件的
key变了,会判定为**"这是两个完全不同的组件"**。
3.2 连锁反应
- 销毁旧组件 :Vue 立即销毁当前的
AirStyleTable实例。 - 创建新组件 :Vue 立即创建一个新的
AirStyleTable实例。 - 触发生命周期 :新实例执行
created()钩子 -> 调用getDeviceList()-> 发送 API 请求。 - 触发防抖拦截 :由于页面初始化或连续输入会导致父组件多次重绘,上述过程在几百毫秒内发生多次。项目的
request.js中配置了防抖逻辑(500ms 内禁止相同请求),从而抛出"请勿重复提交"的错误。
4. 验证方法
在子组件的 created 钩子中添加日志,可以直观地看到组件被反复创建:
javascript
created() {
console.log('%c [验证] 组件被重新创建了', 'color: red', new Date().getTime());
this.getDeviceList();
}
现象:在父组件随便修改一个输入框,控制台就会打印出一条新的"组件被重新创建了"日志。
5. 解决方案
核心原则
Key 必须是稳定且唯一的业务标识,绝不能是不稳定的随机数或时间戳。
修正代码
将 key 绑定为与业务逻辑相关的变量(如表单版本号)。
SampleDetail.vue (父组件)
html
<!-- 正确写法:仅当 tableVersion 变化时才重新渲染组件 -->
<AirStyleTable
:oldData="form"
:key="form.tableVersion"
ref="airStyleTable"
></AirStyleTable>
效果
- 组件复用 :修改省份、日期等常规数据时,
tableVersion不变,Key 不变,组件被复用,不会触发created,API 不会重复调用。 - 按需刷新 :当确实需要切换业务场景(如从"气溶胶"切到"气碘",
tableVersion从 2 变 3)时,Key 变化,组件正常重置,满足业务需求。
6. 避坑总结
- ❌ 永远不要 在
:key中使用Math.random()或new Date()。 - ✅ 如果想强制刷新组件,请使用具体的业务 ID(如
id、version、type)。 - ✅ 如果只是想监听数据变化,请使用
watch或computed,而不是通过销毁组件来"偷懒"。