I have developed a upload functionality, upload component inside accordion. Now I want to retain the data/files that were uploaded in the system when the accordion is collapsed and expanded.
Now I am able to retain the files, but deleting them is throwing the error.
Error:
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.
Design
- Parent component/ (Class component) [parentState]
- Child component/Functional (upload) [maintains local state], sends data that is required by Parent component (Working)
- To retain the state, after collapse and expand of accordion, Moved all the [local state] data to parent state through call back function.
- On component did mount(functional component), took all the data and updated the loca state
- Deleting the files (After opening and closing the accordion), getting the above error.
CODE
/** 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>
);
Updated the Error
The error is in the delete function, as accordion is closed the component is unmounted, but setState is still pointing to its old reference [scope].
Is there a way to point the setstate to newly created component, instead of pointing to unmounted component without moving the state to parent function.
/** deleting the rejected files, removing them from UI */
const deleteRejectedFile = (uuid) => {
setRejectedFiles((updatedRejectedFiles) => {
return updatedRejectedFiles.filter(rejectedFile => rejectedFile.uuid !== uuid);
});
}
