I am creating a multiple image file upload using firebase and react-typescript. My main problem is with async/await. I have a function called uploadFiles
which will save the downloaded URLs into my URLs
state. But the problem is uploadFiles
returning true while the URLs are still loading to set into the state.
My expectation is until setUrls
state new values are placed into the setUrls
state the Async / await will not return true.
I have explained in the video also, https://youtu.be/t6JqasRCPRM
Live code: https://codesandbox.io/s/eloquent-pine-tdv3wf?file=/src/AddProduct.tsx:2777-2941
The main problem is here: setURLs
are taking time to set into the state.
async () => {
await getDownloadURL(uploadTask.snapshot.ref).then((downloadURLs: any) => {
setURLs((prevState: any) => [...prevState, downloadURLs])
console.log("2 File available at", downloadURLs);
});
Also, another problem is that promise is returning true while the URLs are still loading to set into the state.
try {
await Promise.all(promises);
setSuccess(true);
return true;
} catch (e) {
console.error(e);
return false;
}
UploadFiles
function:
const uploadFiles = async (files: any) => {
const promises: any = []
files.map((file: any) => {
const sotrageRef = ref(storage, `files/${file.name}`);
const uploadTask = uploadBytesResumable(sotrageRef, file);
promises.push(uploadTask)
uploadTask.on(
"state_changed",
(snapshot: any) => {
const prog = Math.round(
(snapshot.bytesTransferred / snapshot.totalBytes) * 100
);
setProgress(prog);
},
(error: any) => console.log(error),
async () => {
await getDownloadURL(uploadTask.snapshot.ref).then((downloadURLs: any) => {
setURLs((prevState: any) => [...prevState, downloadURLs])
console.log("2 File available at", downloadURLs);
});
}
);
})
try {
await Promise.all(promises);
setSuccess(true);
return true;
} catch (e) {
console.error(e);
return false;
}
};
uploadWasSuccessful
is returning true I want until the setURls is available my if statement will not go to the next step.
const handleProductSubmit = async (e: any) => {
e.preventDefault()
const uploadWasSuccessful: any = await uploadFiles(images) // returning true but the urls are still loading.
console.log('uploadWasSuccessful', uploadWasSuccessful);
console.log('Success', success);
if (uploadWasSuccessful) {
const newProductValue = { ...productValue, URLs }
console.log(newProductValue, 'productValue');
}
}
CodePudding user response:
The setSuccess(true) call here is not asynchronous. This means its running immediately before the promises are resolved. Add await here to wait for the promises to resolve above.
try {
await Promise.all(promises);
await setSuccess(true); //await
return true;
} catch (e) {
console.error(e);
return false;
}
also make the uploads promises by including await here:
const sotrageRef = ref(storage, `files/${file.name}`);
const uploadTask = await uploadBytesResumable(sotrageRef, file); //added await
await promises.push(uploadTask) //added await
CodePudding user response:
The trick I normally use is that the uploadTask
it itself a promise already, so you can await
it or chain its then
, and just skip the approach with (at least) the third callback:
const uploadFiles = async (files: any) => {
const promises: any = []
files.map((file: any) => {
const storageRef = ref(storage, `files/${file.name}`);
const uploadTask = uploadBytesResumable(storageRef, file);
const urlTask = uploadTask.then(() => storageRef.getDownloadURL); //