为什么数据传着传着变了?
页面结构
组件A
- 组件B1 => 用于设置过滤条件和进行过滤
- 组件B2 => 表格,显示过滤的结果,表格中还有一个列可以用于操作对应行数据的编辑和删除
- 组件B3 => 弹出编辑当前行的表单
我在实现编辑当前行内容并保存功能的时候遇到了些问题,以下是我的实现思路和问题。
在组件A中我声明了一个响应式数据,用于跟踪当前行的数据
const editingEquipmentLedgerForm = ref();
function setEditingEquipmentLedgerForm(newValue) {
editingEquipmentLedgerForm.value = newValue;
}
还有一个方法用于处理点击编辑按钮事件,它将会被传给组件B(表格显示)
function handleEdit(idx, row) {
// todo: 编辑当前行
console.log("edit current row: ", idx, row);
setEditingEquipmentLedgerForm({...toRaw(row)});
console.log("handleEdit: editingEquipmentLedgerForm: ", editingEquipmentLedgerForm);
// 打开编辑弹窗
openEditEquipmentLedgerDrawer();
}
当前编辑的行数据会被传给组件B3(编辑弹窗),当我们打开编辑弹窗的时候,对应行的内容就显示在弹窗中的表单里了。
<EditEquipmentLedgerDrawer
:startLoading="startLoading"
:endLoading="endLoading"
:postEditedEquipmentLedger="postEditedEquipmentLedger"
:editingEquipmentLedgerForm="editingEquipmentLedgerForm"
:closeEditEquipmentLedgerDrawer="closeEditEquipmentLedgerDrawer"
v-model:showEditEquipmentLedgerDrawer="showEditEquipmentLedgerDrawer"
/>
但是当我修改之后,点击保存的时候,就报错了。从我打印的数据可以看到当前修改行的数据变成undefined
了。
async function saveEditedEquipmentLedger(formInstance) {
// todo: 保存新的设备台账信息
if (!formInstance) return;
console.log("formInstance data: ", formInstance);
await formInstance.validate(async (valid, fields) => {
console.log("validate form: ", valid, fields);
if (valid) {
console.log("submit");
// todo: 需要对表单数据进行处理
try {
console.log("editingEquipmentLedgerForm: ", editingEquipmentLedgerForm);
postEditedEquipmentLedger(extractEditedEquipmentLedgerFormData(editingEquipmentLedgerForm));
// 模拟: 上传加载,提示上传成功,然后关闭drawer
startLoading();
await sleep(1);
endLoading();
ElMessage({
message: "设备台账修改成功,您现在可以点击查询获取最新的数据了!",
type: "success",
duration: 1000
})
closeEditEquipmentLedgerDrawer();
formInstance.resetFields();
} catch (error) {
ElMessage({
message: `设备台账修改失败 ${error.message}`,
type: "error",
duration: 1000
})
}
} else {
// 提示验证失败
console.log("error submit", fields);
}
})
}
- 为什么会出现这样的问题呢?该怎么解决呢?
- 我实现编辑保存的方式合理吗?这个组件划分的合理吗?参数传递合理吗?是不是把简单问题变得复杂了?
———————————————————————
这个问题,我简化抽象了一下,相同的逻辑是可以成功保存的,我不知道我的问题出在了哪里?elementplus playground
附:
- github
- stackblitz这个运行不起来
- codesandbox这个可以
这里给的默认值是undefined
所以子组件初始化接受的这个值就是undefined
因为你组件里的editingEquipmentLedgerForm和传过去的editingEquipmentLedgerForm没有关联关系,所以组件里的editingEquipmentLedgerForm没有随着父元素的editingEquipmentLedgerForm改变而改变。
你可以使用
const props = defineProps(...);
声明总的props,在需要的地方使用props.xxx
取值。或者在EditEquipmentLedgerDrawer组件上使用v-if,在openEditEquipmentLedgerDrawer的时候在渲染这个组件1、就像@陟上晴明 说的,不要直接修改props
2、尽量使用props.xxx的形式取值,因为它是动态的,解构出来的值是静态不变的
根据你简化版的案例给你走一下流程,看一下数据在哪,是什么
首先需要知道一点
<script setup>
里面的代码会转化成setup()函数进行执行,setup()会把顶层变量抛出,供组件使用1、在script中打个断点,然后再控制台中找到当前的代码位置,看下setup转化后的结果是什么
这个setup就是,打印出来就是下面的代码(简化版),可以看出来没有editingItem, closeDrawer, simulateOperation这些props带过来的值(这里可能是关键,需要看下转换代码是什么逻辑),所以props中解构的值只在setup函数作用域中存在和使用且他们的值是固定的
2、继续往下走,看下组件执行完毕后有哪些数据
3、点击编辑按钮后的数据
4、点击按钮后,看下执行script中的函数,数据是什么
到此,整个数据转化的流程应该很清楚明了了。如果想要明白具体原理,建议有时间看下源码。