Robert Berge
Robert Berge

Reputation: 375

How can I return the download URL of an image uploaded to firebase storage

I want to upload an image to firebase (which is working), then return the download URL of the image and store it as a string.

Here is my code:

uploadImage = async (uri, imageName) => {
    const response = await fetch(uri);
    const blob = await response.blob();

    firebase.storage().ref().child(imageName).put(blob)
      .then(snap => {
        return snap.ref.getDownloadURL();
      })
      .then(downloadURL => {
        return downloadURL;
      })
      .catch(error => {
        console.log(`An error occurred while uploading the file.\n\n${error}`);
      });
  }

The image uploads to firebase storage just fine. At the moment it just shows this when I try write the URL of the uploaded image to the database: https://ibb.co/WHHHxBY

Here is the block of code where I create the user record:

  firebase
    .auth()
    .createUserWithEmailAndPassword(this.state.email, this.state.password)
    .then(userCredentials => {
      let imageUrl = '';

      let db = firebase.database().ref('users/' + userCredentials.user.uid);

      if (this.state.image) {
        imageUrl = this.uploadImage(this.state.image.uri, `images/user-${userCredentials.user.uid}`);
      }

      db.set({
        email: this.state.email,
        imageUrl: imageUrl,
        username: this.state.username
      });

      return userCredentials.user.updateProfile({
        displayName: this.state.username
      });
    })
    .catch(error => this.setState({ errorMessage: error.message }));

Upvotes: 0

Views: 900

Answers (1)

Renaud Tarnec
Renaud Tarnec

Reputation: 83181

In your uploadImage function, you are chaining the promises but you don't return the chain. You should adapt it as follows:

uploadImage = async (uri, imageName) => {
    const response = await fetch(uri);
    const blob = await response.blob();

    return firebase.storage().ref().child(imageName).put(blob)  // <-- Here return the chain
      .then(snap => {
        return snap.ref.getDownloadURL();
      })
      .then(downloadURL => {
        return downloadURL;
      })
      .catch(error => {
        console.log(`An error occurred while uploading the file.\n\n${error}`);
      });
  }

However, you could transform this code in async/await "style", as follows:

uploadImage = async (uri, imageName) => {

    try {
        const response = await fetch(uri);
        const blob = await response.blob();

        const snap = await firebase.storage().ref().child(imageName).put(blob);

        const downloadURL = await snap.ref.getDownloadURL();

        return downloadURL;

    } catch (e) {
        console.error(e);
        throw e;
    }

}

Then, since this uploadImage function is asynchronous you should adapt the way you call it. I suggest to modify the other part of your code as follows:

try {
     const userCredentials = await firebase
        .auth()
        .createUserWithEmailAndPassword(this.state.email, this.state.password);

     let imageUrl = '';

     const db = firebase.database().ref('users/' + userCredentials.user.uid);

     if (this.state.image) {

        imageUrl = await this.uploadImage(this.state.image.uri, `images/user-${userCredentials.user.uid}`);

        await db.set({
            email: this.state.email,
            imageUrl: imageUrl,
            username: this.state.username
          });


          return userCredentials.user.updateProfile({
            displayName: this.state.username
          });

     }
     //You should probably manage the else case

} catch (e) {
     this.setState({ errorMessage: e.message })
}

Upvotes: 1

Related Questions