0

The following function extracts images stored on a firebase storage and logs their URL to the console. I have tried multiple ways to pass the URL extracted to the Image for display on the screen. All images URL is successfully logged but won't display.

EDITED: Added the full code

The listFilesAndDirectories function was placed outside the const Gallery declaration, putting function inside Gallery still doesn't change anything. I also tried passing the state to a variable and passing as the uri to no avail


import React, {setState} from 'react';
import {
  SafeAreaView,
  StyleSheet,
  ScrollView,
  View,
  Text,
  StatusBar,
  TouchableOpacity,
  Image,
} from 'react-native';
import Header from '../shared/header';
import firebase from '@react-native-firebase/app';
import storage from '@react-native-firebase/storage';
import Hamburg from '../shared/hamburg';
import SharedStyles from '../shared/sharedStyle';
import {DrawerActions, useNavigation} from '@react-navigation/native';

const Gallery: () => React$Node = () => {
  const navigation = useNavigation();

  function listFilesAndDirectories(reference, pageToken) {
    return reference.list({pageToken}).then(result => {
      result.items.forEach(ref => {
        // call getDownloadURL on every object reference
        ref.getDownloadURL().then(url => {
          setState({url: url});
          console.log(
            `File is referenced from :\n ${storageReference}:\n\n Image URL is:\n ${url}`,
          );
        });
      });

      if (result.nextPageToken) {
        return listFilesAndDirectories(reference, result.nextPageToken);
      }

      return Promise.resolve();
    });
  }

  const storageReference = firebase
    .storage()
    .refFromURL('gs://app404.com/images');

  listFilesAndDirectories(storageReference).then(() => {
    // storageReference.getDownloadURL();
    console.log('Started listing image download urls');
  });

  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <View style={SharedStyles.header}>
          <TouchableOpacity
            onPress={() => {
              navigation.dispatch(DrawerActions.openDrawer());
            }}>
            <Hamburg />
          </TouchableOpacity>
          <Header title="Gallery" />
        </View>
        <ScrollView contentInsetAdjustmentBehavior="automatic">
          <View style={styles.container}>
            <View style={styles.sectionContainer}>
              <View>
                <Text>
                  Welcome to my Gallery!
                </Text>
                <Image
                  source={{
                       uri: {url}   //url is not defined
                  }}
                  style={styles.fetchedImage}
                />
              </View>
            </View>
          </View>
        </ScrollView>
      </SafeAreaView>
    </>
  );
};


EDIT 2

const Gallery: () => React$Node = () => {
  const navigation = useNavigation();
  const [downloadUrl, setDownloadUrl] = useState({url: undefined});
  console.log(`URL should be undefined at this point ${downloadUrl}`);

  function listFilesAndDirectories(reference, pageToken) {
    return reference.list({pageToken}).then(result => {
      result.items.forEach(ref => {
        // call getDownloadURL on every object reference
        ref.getDownloadURL().then(url => {
          setDownloadUrl({url});
          console.log(`Image URL is:\n ${url}`);
        });
      });

and inside the image component:

           <Image
                  source={{
                    uri: {...downloadUrl.url},
                  }}
                  style={styles.fetchedImage}
                />
web_walkerX
  • 840
  • 10
  • 19

1 Answers1

1

Since the URLs are being determined through asynchronous operations, you can't return them to the render method. Instead you'll need to store them in the state, and render them from there:

function listFilesAndDirectories(reference, pageToken) {
  reference.list({pageToken}).then(result => {
    result.items.forEach(ref => {
      ref.getDownloadURL().then(url => {
        setState({ url: url });
      });
    });

    if (result.nextPageToken) {
      listFilesAndDirectories(reference, result.nextPageToken);
    }
  });
}

const storageReference = firebase
  .storage()
  .refFromURL('gs://app404.appspot.com/images');

listFilesAndDirectories(storageReference);

And then:

  <View>
    <Text>
      Welcome to my Gallery! Come back for more content.
    </Text>
    <Image
      source={{
        uri: {url} 
      }}
      style={styles.fetchedImage}
    />
  </View>

If you want to wait for the multiple images, have a look here: How to list all the names and download Urls from Firebase using React JS? or Firebase storage: download images to and put to img src in React map

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • url is still not accessible from inside image source, returns 'url is not defined' – web_walkerX Jun 15 '20 at 11:36
  • My guess is that this is because no initial state is set. You might want to initialize the `url` in the state in your constructor, as shown here: https://stackoverflow.com/questions/37782403/set-initial-react-component-state-in-constructor-or-componentwillmount. – Frank van Puffelen Jun 16 '20 at 23:34
  • i used the key : value pair to initialize the url and then the spread operator , it stills logs the url but doesnt display image – web_walkerX Jun 17 '20 at 01:11