Vue3 动态ref问题及解决
作者:linab112
Vue3动态ref在组件卸载后保留key,值置为null,需手动检查null以避免错误,不可删除key,此为设计行为,旨在维护响应式结构完整性及性能优化
1.问题描述
在Vue 3项目中,当使用动态ref来引用组件时,删除组件后发现ref对象中对应的key仍然存在,只是值变为`null`,而不是完全删除该key。
在一个可拖拽的卡片列表组件中:
- 使用动态ref来引用每个卡片中的数据列表组件
- 当删除卡片时,需要同时清理对应的ref引用
- 发现删除后ref对象中key仍存在,值为`null`
2.示例代码
<template>
<div>
<a-card v-for="item in dragList" :key="item.id">
<!-- 动态ref的使用 -->
<data-list
:ref="el => { dataListRef[item.id] = el }"
:doc-id="item.id"
:open-type="item.openType"
/>
</a-card>
</div>
</template><script setup lang="ts">
import { ref } from 'vue';
const dragList = ref<any[]>([]);
const dataListRef = ref<Record<string, any>>({});
// 删除卡片方法
function remove(index: number) {
const current = dragList.value[index];
// 处理编辑状态
if (current.openType === OPEN_WRITE) {
const docIds = [current.id];
closeDocEntry(docIds);
}
// 从列表中移除
dragList.value.splice(index, 1);
// 更新其他项目的源列表
for (let ele of dragList.value) {
const oldSourceList = ele.sourceList;
ele.sourceList = oldSourceList.filter((item: any) => item.sourceId !== current.id);
}
// Vue 会自动处理动态 ref 的清理,无需手动删除,即使执行了删除方法,也不会删除key
// dataListRef.value[current.id] 会自动变为 null
}
// 刷新所有数据列表
function reflushAllDragList() {
Object.keys(dataListRef.value).forEach((key: string) => {
// 过滤掉已经被删除的组件(值为null的情况)
if (dataListRef.value[key]) {
dataListRef.value[key].refresh();
}
});
}
</script>说明:
①可以使用数组或者对象存储组件的ref对象实例,因为组件是循环生成的,所以每个组件的ref对象需要通过这种方式进行存储。
② 循环生成的多个组件可以通过点击删除按钮进行删除,当组件删除时原本想删除ref对象中的组件对应的ref对象,但发现无法删除,最后的结果是key存在,value为null
3.原因分析
Vue 3中的动态ref机制有以下特点:
- 组件挂载时:动态ref会自动将组件实例赋值给指定的key
- 组件卸载时:Vue会自动将对应的ref值设置为`null`,但**不会删除key**
- 响应式处理:Vue的响应式系统会在组件生命周期中自动管理ref的状态
为什么key不会被删除
这是Vue 3的设计行为,不是bug:
- Vue需要保持ref对象的响应式结构完整性
- 避免在组件频繁挂载/卸载时产生不必要的响应式触发
- 提供了更好的性能优化
4.解决方案
因为无法删除,所以在后续使用ref对象时,需要进行判断是否为null,如果不为null,则执行相关方法。
function reflushAllDragList() {
Object.keys(dataListRef.value).forEach((key: string) => {
// 过滤掉已经被删除的组件(值为null的情况)
// 当删除card时,Vue会自动把dataListRef的对应key的值设置为null
// 不用进行手动删除,即使手动删除,key也存在
if (dataListRef.value[key]) {
dataListRef.value[key].refresh();
}
});
}5.总结
Vue 3的动态ref在组件卸载时会自动将值设置为`null`但保留key,这是正常的设计行为。
正确的处理方式是:
- 不要尝试手动删除ref中的key
- 在使用ref时进行null检查
- 信任Vue的自动管理机制
这样可以确保代码的稳定性和可维护性。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
