如何在异常错误后回滚项/集合值,避免集合中item被修改?
解决方案
核心问题原因
你遇到的同步修改问题,本质是JavaScript对象的引用特性:item直接指向了colect数组里的某个对象,修改item的属性时,其实是在操作原数组里对象的内存地址,所以colect会跟着变化。要解决这个问题,关键是断开引用,同时保存原始值用于回滚。
具体解决步骤
赋值时深拷贝对象,断开引用
不管是初始化item,还是通过q-select选中新值时,都要对colect里的对象做深拷贝,让item成为一个独立的对象,不再和colect共享内存。比如修改
q-select的绑定逻辑,用@update:model-value代替直接v-model,在回调里处理拷贝:<q-select :model-value="item" @update:model-value="onSelectItem" :options="colect"></q-select> <q-input v-model="item.name"></q-input>对应的脚本部分:
const colect = ref([{ id: 1, name: "示例1" }, { id: 2, name: "示例2" }]); const item = ref({}); // 保存原始值用于回滚 const originalItem = ref({}); // 处理选中事件 const onSelectItem = (selected) => { // 用structuredClone做深拷贝,支持嵌套对象 item.value = structuredClone(selected); originalItem.value = structuredClone(selected); }; // 如果是初始化时要给item赋值,同样要拷贝 onMounted(() => { if (colect.value.length > 0) { onSelectItem(colect.value[0]); } });如果你的对象没有嵌套结构,也可以用扩展运算符
{...selected}简化,但structuredClone兼容性更好,适合大多数场景。保存失败时回滚到原始值
当调用接口保存出错时,直接把之前保存的originalItem拷贝赋值给item即可恢复:const saveToDatabase = async () => { try { // 模拟接口请求 await fetch("/api/save", { method: "POST", body: JSON.stringify(item.value), }); // 保存成功后,更新原始值为最新状态 originalItem.value = structuredClone(item.value); console.log("保存成功"); } catch (err) { // 保存失败,回滚 item.value = structuredClone(originalItem.value); console.error("保存失败,已回滚数据"); } };
额外提示
- 不要用浅拷贝(比如
Object.assign)处理嵌套对象,否则嵌套的子对象还是会共享引用,导致同步修改。 - 如果项目里经常需要深拷贝,可以封装一个工具函数,或者用
lodash.cloneDeep(如果已经引入了lodash)。
内容的提问来源于stack exchange,提问作者Rafa Calderón
相关产品推荐
相关产品推荐

