Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Listening to async upload task to handle loading state

I’m trying to set a loading state according to the state of sending. If the image is sent I will simply insert a loading indicator. Although whenever the task is running, I’m receiving a done (.then()) before the task actually finishes, and the loading indeicator doesnt work as expected:

The task:

export async function storeImage(uri: string, description: string) {
  const reference = ref(storage, `posts/${auth.currentUser!.uid}/${uuid.v4()}`);

  const blob: any = await new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.onload = function () {
      resolve(xhr.response);
    };
    xhr.onerror = function (e) {
      console.log(e);
      reject(new TypeError('Network request failed'));
    };
    xhr.responseType = 'blob';
    xhr.open('GET', uri, true);
    xhr.send(null);
  });

  const uploadTask: any = uploadBytesResumable(reference, blob);

  uploadTask.on(
    'state_changed',
    (snapshot: any) => {
      const progress = snapshot.bytesTransferred / snapshot.totalBytes;
      console.log('Upload is ' + progress + '% done');
      switch (snapshot.state) {
        case 'paused':
          // console.log('Upload is paused');
          break;
        case 'running':
          console.log('Upload is running');
          break;
      }
    },
    (error: any) => {
      // Handle unsuccessful uploads
      console.log('Storage error', error);
      blob.close();
    },
    () => {
      getDownloadURL(uploadTask.snapshot.ref).then(async (downloadURL) => {
        console.log('File available at', downloadURL);
        await addImageReferenceToFirestore({ url: downloadURL, description });
      });

      blob.close();
    }
  );
}

if I insert an await on const uploadTask: any = uploadBytesResumable(reference, blob);
I get this error, and it stays loading forever:

[Unhandled promise rejection: TypeError: undefined is not a function (near '...uploadTask.on...')]

This is my component:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

export function Post({ navigation, ...rest }: any) {
  const [description, setDescription] = useState('');
  const [loading, setLoading] = useState(false);

  async function createPost() {
    setLoading(true);
    await storeImage(rest.route.params.images[0], description).then(() => console.log('done'));
    setLoading(false);
  }

  return (
    <Container>
      {loading ? (
        <Circle size={RFValue(25)} indeterminate={true} color="red" />
      ) : (
        <CreateBar
          text={i18n.t('createPost.title')}
          iconName="CreatePost"
          onPressIcon1={() => navigation.goBack()}
          onPressIcon2={() => createPost()}
        />
      )}
      <ContainerDescription>
        <ImageContainer>
          <Image
            source={{ uri: rest.route.params.images[0] }}
            style={{ width: '100%', height: '100%', borderRadius: 8 }}
          />
        </ImageContainer>

        <TextAreaContainer>
          <InputText
            placeholder={i18n.t('createPost.describe')}
            onChangeText={(newText: string) => setDescription(newText)}
          />
        </TextAreaContainer>
      </ContainerDescription>

      <LightDivider />

>Solution :

You are receiving a done from the console.log before the task finishes, because you’re not actually awaiting for the task to finish. You are just awaiting the blob part.

If you just want to get to the final result of the uploaded image URL, without displaying any progress, then you should also await for the uploadTask.on to finish. Wrap uploadTask.on inside a Promise, resolve on successfully uploading the image and reject on errors:

await new Promise((resolve, reject) => {
  uploadTask.on(
    'state_changed',
    (snapshot: any) => {
      const progress = snapshot.bytesTransferred / snapshot.totalBytes;
      console.log('Upload is ' + progress + '% done');
      switch (snapshot.state) {
        case 'paused':
          // console.log('Upload is paused');
          break;
        case 'running':
          console.log('Upload is running');
          break;
      }
    },
    (error: any) => {
      // Handle unsuccessful uploads
      console.log('Storage error', error);
      blob.close();
      reject(error);
    },
    () => {
      getDownloadURL(uploadTask.snapshot.ref)
        .then(async (downloadURL) => {
          console.log('File available at', downloadURL);
          try {
            await addImageReferenceToFirestore({ url: downloadURL, description });
          } catch (err) {
            reject(err);
          }

          resolve();
        })
        .catch((err) => reject(err));

      blob.close();
    },
  );
});

And you should also add a try/catch/finally block to your createPost function. Otherwise if the Promise is rejected, the setLoading(false) would never be executed:

async function createPost() {
  try {
    setLoading(true);
    await storeImage(rest.route.params.images[0], description);
  } catch (err) {
    console.error(err);
  } finally {
    setLoading(false);
  }
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading