Reputation: 85
I am trying to upload files and show progress while the files are uploading, what I am doing is
when the user selects the files from the input I have an onChange
listener that will take the files and build a new state with objects with 2 fields file and progress like this:
const [files,setFiles] = useState([]);
const handleFileUpload = async (e) => {
const fileList = Array.from(e.target.files);
const filesStructure = fileList.map((file: any) => ({
progress: 0,
file,
}));
const clonedFiles = [...files, ...filesStructure];
setFiles(clonedFiles);
filesStructure.forEach((fileItem) => {
uploadFile(fileItem.file, post.id);
});
}
e.target.value = "";
};
now in my uploadFile
I want to update the progress for each file but if I check there the state is an empty array
const uploadFile = async (file, postId: string) => {
console.log("files are:", files);
setIsLoading(true);
const formData = new FormData();
formData.append("file", file);
formData.append("post_id", postId);
try {
const onprogress = (event) => {
clonedFileItem.progress = Math.round((event.loaded * 100) / event.total);
const clonedFiles = [...files];
clonedFiles[index] = clonedFileItem;
setFiles(clonedFiles);
};
const res = await uploadFileService(formData, onprogress);
} catch (error) {
console.log(error.message);
} finally {
setIsLoading(false);
}
};
I am not very sure how should I approach this problem? I need to have access to the updated state inside uploadFile
and inside the onprogress
function.
Upvotes: 3
Views: 44
Reputation: 299
As a general rule, with React every time there is a so called "side effect", you should use a useEffect hook.
What I suggest to you is using a useEffect hooks that executes its function when the file variable (the one that you defined with your useState hook) changes. Inside this effect you can run whatever logic you want in order to change the ui accordingly
Upvotes: 0
Reputation: 44078
Generally, you are using a lot of variable references here, that will all at some points run stale.
files
will reference the files
array at the time uploadFile
was defined before it was called.
You can get around that in many cases by just using the callback notation.
const onprogress = (event) => {
setFiles(oldFiles => {
clonedFileItem.progress = Math.round((event.loaded * 100) / event.total);
const clonedFiles = [...oldFiles];
clonedFiles[index] = clonedFileItem;
return clonedFiles
}
};
Upvotes: 3