我开发了一个上传功能,在 Accordion 中上传组件。现在我想保留 Accordion 折叠和展开时上传到系统中的数据/文件。
现在我可以保留文件,但删除它们会引发错误。
错误:
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
设计
- 父组件/(类组件)[parentState]
- 子组件/Functional(上传)[维护本地状态],发送父组件(工作)所需的数据
- 为了保留状态,在 Accordion 折叠和展开后,通过回调函数将所有[本地状态]数据移动到父状态。
- 在组件上挂载(功能组件),获取所有数据并更新本地状态
- 删除文件(打开和关闭 Accordion 后),出现上述错误。
代码
/** set the state locally from parent state
* component did mount
*/
useEffect(() => {
if (parentState[`${field}acceptedFiles`]) {
setAcceptedFiles([...parentState[`${field}acceptedFiles`]]);
}
if (parentState[`${field}rejectedFiles`]) {
console.log('REJECTED FILES', parentState[`${field}rejectedFiles`]);
setRejectedFiles([...parentState[`${field}rejectedFiles`]]);
}
}, []);
/** maintain the state in parent state
* this is used retain the state from parent state
*/
useEffect(() => {
const afile = {
[`${field}acceptedFiles`]: acceptedFiles
};
onChange(afile);
}, [acceptedFiles]);
useEffect(() => {
const rfile = {
[`${field}rejectedFiles`]: rejectedFiles
};
onChange(rfile);
}, [rejectedFiles]);
/** deleting the rejected files, removing them from UI */
const deleteRejectedFile = (uuid) => {
setRejectedFiles((updatedRejectedFiles) => {
return updatedRejectedFiles.filter(rejectedFile => rejectedFile.uuid !== uuid);
});
}
/** deleting the accepted files, removing them from UI and removing from attachments
* Send back uploadAttachments to parent state */
const deleteAcceptedFile = (uuid) => {
setAcceptedFiles((updatedAcceptedFiles) => {
return updatedAcceptedFiles.filter(acceptedFile => acceptedFile.uuid !== uuid);
});
}
const handleRejectedFiles = (rejected, docTypeError) => {
const files = rejected.map(file => {
const uuid = getUUID();
return {
name: file.name,
uuid,
rightIconItems: {
onIconClick: () => deleteRejectedFile(uuid)
},
}});
setRejectedFiles([...rejectedFiles, ...files]);
}
const handleAcceptedFiles = (accepted) => {
const files = accepted.map((file) => {
const uuid = getUUID();
const { PENDING, INFO } = constants;
return {
...file,
file: file,
uuid,
rightIconItems: {
onIconClick: () => deleteAcceptedFile(uuid)
}
}
})
setAcceptedFiles([...acceptedFiles, ...files]);
}
const onFileSelected = (accepted, rejected) => {
handleAcceptedFiles(accepted);
handleRejectedFiles(rejected);
};
return (
<DragAndDropContainer>
<FileSelector
onFileSelected={onFileSelected}
acceptedFiles={acceptedFiles}
rejectedFiles={rejectedFiles}
/>
</DragAndDropContainer>
);
更新了错误
错误出在 delete 函数中,因为 accordion 已关闭,组件已卸载,但 setState
仍指向其旧引用 [scope]。
有没有办法将 setstate
指向新创建的组件,而不是在不将状态移动到父函数的情况下指向未安装的组件。
/** deleting the rejected files, removing them from UI */
const deleteRejectedFile = (uuid) => {
setRejectedFiles((updatedRejectedFiles) => {
return updatedRejectedFiles.filter(rejectedFile => rejectedFile.uuid !== uuid);
});
}
最佳答案
此错误是由于引用删除方法引起的。 deleteRejectedFile
和 deleteAcceptedFile
函数的 setstate
方法指向已卸载的组件,而不是指向已安装的组件。
所以我创建了一个新的图标引用
useEffect(() => {
if (parentState[`${field}acceptedFiles`]) {
const newAcceptedReferences = parentState[`${field}acceptedFiles`].map((accepted) => {
const rightIconItems = {
onIconClick: () => deleteAcceptedFile(accepted.uuid)
};
return {
...accepted,
rightIconItems
}
});
setAcceptedFiles(newAcceptedReferences);
}
if (parentState[`${field}rejectedFiles`]) {
const newRejectedReferences = parentState[`${field}rejectedFiles`].map((rejected) => {
const rightIconItems = {
onIconClick: () => deleteRejectedFile(rejected.uuid)
};
return {
...rejected,
rightIconItems
}
});
setRejectedFiles(newRejectedReferences);
}
}, []);
关于javascript - 展开和折叠后保持状态 |导致 React 状态更新错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73487308/