'Setting image source to Firebase Storage URL with React Native

So I am trying to set a image source to the download url that I get back from Firebase Storage...the issue is that it is not showing the image but the console and download url both show correct Storage urls to pictures... here is my code that I currently have:

this.state = {
      itemDataSource: ds,
      modalVisible: false,
      user: undefined,
      imgSource: undefined,
    };

  getTrucks(truckRef, storageRef) {
    truckRef.once('value', (snap) => {
      console.log(snap.val());
      // console.log(snap.key);
      let trucks = [];
      snap.forEach((trucksSnap) => {
        console.log(trucksSnap.key);
        uid = trucksSnap.key;
        this.setState({user: uid});
        trucksSnap.forEach((truckSnap) => {
          console.log(truckSnap.key);
          console.log(truckSnap.val());
          let truck = truckSnap.val();
          trucks.push({
            uid: uid,
            name: truck.name,
            food: truck.foodType,
            desc: truck.description,
            menu: truck.menu,
            phone: truck.phone, 
          });
        });
      });
      console.log(trucks);
      this.setState({
        itemDataSource: this.state.itemDataSource.cloneWithRows(trucks)
      });
    });
  }

getPics(storageRef) {
        setTimeout(() => {
        storageRef.ref('trucks/' + this.state.user + '/pic-1').getDownloadURL()
          .then((url) => {
            console.log(url);
            this.setState({imgSource: url});
          });
        }, 3000);
      }

<Image
  source={{uri: this.state.imgSource}} 
  style={styles.iosCardImage}/>

the Image is in the render function and there is no image that shows up on screen but the console shows it other wise as the actual url that I can click on and see the image

console log

I did look at other example questions though there was not an actual working answer posted or checked as correct.

React-Native: Download Image from Firebase Storage

Load and return an image from Firebase database/storage in React Native

React Native is at version 0.45.1 & Firebase is at version 4.1.3

Can someone please help me to set the source tag correctly who has done it before? Thank you



Solution 1:[1]

For future reference for other people here is the way(s) to do this... you do however as @marcST mentioned you have to set height and width in your styles either with React Natives inline styling or with and external stylesheet. Here are the 2 methods you can accomplish this, I am posting this since there is not a valid answer here on StackOverflow of how to do this correctly in React Native

1st way: so there are a couple of things you will need to note about this way.

  1. This is when you use .push() to add data to your Firebase database/storage
  2. you first need state to be set to undefined || null || ''
  3. you should use shouldComponentMount() because some of the data will not come in before the component mounts to the screen
  4. you will need to JSON.stringify the URL coming back from your getDownloadURL()

this.state = { itemDataSource: ds, modalVisible: false, user: undefined, imgSource: undefined, };

  shouldComponentUpdate(nextState) {
    return nextState.imgSource !== this.state.imgSource;
  }

  getTrucks(truckRef, storageRef) {
    truckRef.once('value', (snap) => {
      console.log(snap.val());
      // console.log(snap.key);
      let trucks = [];
      snap.forEach((trucksSnap) => {
        console.log(trucksSnap.key);
        uid = trucksSnap.key;
        this.setState({user: uid});
        trucksSnap.forEach((truckSnap) => {
          console.log(truckSnap.key);
          console.log(truckSnap.val());
          let truck = truckSnap.val();
          trucks.push({
            uid: uid,
            name: truck.name,
            food: truck.foodType,
            desc: truck.description,
            menu: truck.menu,
            phone: truck.phone, 
          });
        });
      });
      console.log(trucks);
      this.setState({
        itemDataSource: this.state.itemDataSource.cloneWithRows(trucks)
      });
    });
  }

getPics(storageRef) {
        setTimeout(() => {
        storageRef.ref('trucks/' + this.state.user + '/pic-1').getDownloadURL()
          .then((url) => {
            console.log(url);
            let imgURL = JSON.stringify(url)
            this.setState({imgSource: imgURL});
          });
        }, 3000);
      }

<Image
  source={{uri: this.state.imgSource}} 
  style={styles.iosCardImage}/>

2nd way:

  1. use .set() to add data to your firebase database
  2. I used .set() to add the URL coming back on load to save into my Firebase database under an 'image' folder... see picture below code
  3. When you put download URL's into your database you do not need to run the snapshot.forEach multiple times just to access your data, because you bypass the unique ID set by pushing that Firebase sets every time you push.
  4. When you pull data from the database with image URL's you do not need to JSON.stringify them to add as image URI.
  5. You do not need to set state to add the URL as the URI source
  6. You can now use dot notation to access your data as you would a normal JSON object

this is my component code that solves this...

  getTrucks(truckRef) {
    truckRef.on('value', (snap) => {
      console.log(snap.val());
      let truck = snap.val();
      let trucks = [];
      snap.forEach((truck) => {
        trucks.push({
          uid: truck.key,
          name: truck.val().data.name,
          food: truck.val().data.foodType,
          desc: truck.val().data.description,
          menu: truck.val().data.menu,
          phone: truck.val().data.phone,
          pic1: truck.val().mainImage.pic1,
          pic2: truck.val().image2.pic2,
          pic3: truck.val().image3.pic3,
          pic4: truck.val().image4.pic4,
          pic5: truck.val().image5.pic5,
          pic6: truck.val().image6.pic6
        });
        console.log(trucks);
      });
      this.setState({
        itemDataSource: this.state.itemDataSource.cloneWithRows(trucks),
      });
    });
  }

  <Image
   source={{uri: truck.pic1}} 
   style={styles.iosCardImage}/>

this is the database code with the set method I am talking about

let url = task.snapshot.downloadURL;
trucksRef.child(user).child('mainImage').set({pic1: url});

 trucksRef.child(firebaseUser.uid).child('data').set({
    name: $('#name').val(),
    foodType: $('#food').val(),
    description: $('#description').val(),
    address: $('#address').val(),
    city: $('#city').val(),
    zip: $('#zip').val(),
    phone: $('#phone').val(),
    menu: $('#menu').val(),
    });

the picture in reference to what happens in your database if you use .set() instead of .push() my database

If you have other questions please let me know about this

Solution 2:[2]

I had a problem similar to this where I had the correct download URL but the Image wasn't showing. It's quite likely the Image isn't being displayed because of a styling issue. What's in iosCardImage? If you haven't already, try defining width and height. Try doing:

<Image
 source={{uri: this.state.imgSource}} 
 style={{ height: 200 }}/>

and see if the Image shows.

Solution 3:[3]

I fixed the problem with this... path/android/app/src/main/AndroidManifest.xml

android:largeHeap="true

<application
  android:name=".MainApplication"
  android:label="@string/app_name"
  android:icon="@mipmap/ic_launcher"
  android:roundIcon="@mipmap/ic_launcher_round"
  android:allowBackup="false"
  android:largeHeap="true"
  android:theme="@style/AppTheme">

I see android:largeHeap="true" as an accepted solution very often but this is not the right solution. We just enlarge the heap (if the target device has an ability to do so) which means that your application might work longer but might fail eventually anyway.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 T. Evans
Solution 2 marcst
Solution 3 Kenap