const handleItinerary = (e, type) => {
var index = parseInt(e.target.name);
let arr = [...itinerary];
if (type === "imageUrl") {
const date = new Date().getTime();
const storageRef = ref(storage, `${date}`);
uploadBytes(storageRef, e.target.files[0]).then((snapshot) => {
getDownloadURL(storageRef).then((downloadURL) => {
arr[index]["imageUrl"] = downloadURL;
});
});
}
setitinerary(arr);
}
In the above code I am trying to upload an image in firebase storage using uploadBytes function and after uploading the image I get the downloadURL where image is stored, I want to put its value in arr[index]["imageUrl"], but the arr[index]["imageUrl"] is getting updated first before getting the downloadURL and I am getting error that downloadURL is undefined, so how to resolve this issue? I am using react 18 and firebase version 9.
CodePudding user response:
When using then()
to run code in response to an asynchronous operation being completed, any code that needs to run upon completion has to be inside that then()
callback.
So
const handleItinerary = (e, type) => {
var index = parseInt(e.target.name);
let arr = [...itinerary];
if (type === "imageUrl") {
const date = new Date().getTime();
const storageRef = ref(storage, `${date}`);
uploadBytes(storageRef, e.target.files[0]).then((snapshot) => {
getDownloadURL(storageRef).then((downloadURL) => {
arr[index]["imageUrl"] = downloadURL;
setitinerary(arr);
});
});
}
}
To make this a bit more familiar, you can mark the `` as async
and use await
inside it:
const handleItinerary = async (e, type) => {
var index = parseInt(e.target.name);
let arr = [...itinerary];
if (type === "imageUrl") {
const date = new Date().getTime();
const storageRef = ref(storage, `${date}`);
const snapshot = await uploadBytes(storageRef, e.target.files[0]);
const downloadURL = await getDownloadURL(storageRef);
arr[index]["imageUrl"] = downloadURL;
setitinerary(arr);
}
}
Note that this doesn't change anything about the actual behavior and all asynchronous calls are still executed asynchronously. It is merely a more familiar way to write the code.
If you have a list of images to upload, be sure to either use for of
instead of forEach
or Promise.all
to detect when all asynchronous operations are done.
CodePudding user response:
You can move the code that updates the arr[index]["imageUrl"]
value inside the then
block where you retrieve the downloadURL
. This will ensure that the arr[index]["imageUrl"]
value is only updated after the downloadURL
has been retrieved.
const handleItinerary = (e, type) => {
var index = parseInt(e.target.name);
let arr = [...itinerary];
if (type === "imageUrl") {
const date = new Date().getTime();
const storageRef = ref(storage, `${date}`);
uploadBytes(storageRef, e.target.files[0]).then((snapshot) => {
getDownloadURL(storageRef).then((downloadURL) => {
arr[index]["imageUrl"] = downloadURL;
setitinerary(arr);
});
});
}
}