skip to Main Content
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.

2

Answers


  1. 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.

    Login or Signup to reply.
  2. 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);
          });
        });
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search