Home > database >  React Promise is not awaited
React Promise is not awaited

Time:07-20

I have an input of type image which accepts multiple images. I save this in a React Hook and want to upload it to my Firebase Storage after the user presses Upload. For this I use a promise and an async method. Once the array of images has been traversed, I want to display some output in the log. However, React immediately jumps to the "Then" block for the console output, which of course is then NULL. What am I doing wrong ?

const uploadImg = async () => {

setUploadIsDone(false);

if (file.length) {
  asyncFuncUploadToMongoDb().then((data) => {
    console.log(data); // Is called immediately 
    setProgress(0);
    setUploadIsDone(true);
  });
 }
};



const asyncFuncUploadToMongoDb = async () => {
const storage = getStorage();

return Promise.all(
  file.map((f) => {
    const articelImagesRef = ref(
      storage,
      "articelImg/"   new Date()   ".jpg"
    );
    const uploadTask = uploadBytesResumable(articelImagesRef, f);

    uploadTask.on(
      "state_changed",
      (snapshot) => {
        const progress =
          (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
        setProgress(progress);
        // eslint-disable-next-line default-case
        switch (snapshot.state) {
          case "paused":
            console.log("Upload is paused");
            break;
          case "running":
            console.log("Upload is running");
            break;
        }
      },
      (error) => {
        console.log(error);
      },
      () => {
        getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => {
          setImgUrl([...imgUrl, downloadURL]);
        });
      }
    );
   })
  );
 };

CodePudding user response:

Inside your file.map method, you are not returning any promise.

You should return each promise from the map method, in order to handle all of them with Promise.all.


Since you have a listener callback (and not a promise for your task), you could create and return a brand new promise to handle each map finish.

Simple example based on your code (see comments)

return Promise.all(
  file.map((f) => {
    // Create and return a new Promise for each file
    return new Promise((resolve, reject) => {
      const articelImagesRef = ref(
        storage,
        "articelImg/"   new Date()   ".jpg"
      );
      const uploadTask = uploadBytesResumable(articelImagesRef, f);

      uploadTask.on(
        "state_changed",
        (snapshot) => {
          const progress =
            (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
          setProgress(progress);
          // eslint-disable-next-line default-case
          switch (snapshot.state) {
            case "paused":
              console.log("Upload is paused");
              break;
            case "running":
              console.log("Upload is running");
              break;
          }
        },
        (error) => {
          console.log(error);
          // Reject the promise when fail
          reject(error);
        },
        () => {
          getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => {
            setImgUrl([...imgUrl, downloadURL]);

            // Resolve the promise when ready
            resolve(downloadUrl); 
          }).catch(error => {
            // Reject the promise getting download url fail
            reject(error);
          });
        }
      );
    });
  })
);
  • Related