DEV Community

Cover image for Upload Files Using React Native and Firebase (Part 3)
Younes Henni
Younes Henni

Posted on

Upload Files Using React Native and Firebase (Part 3)

Originally published in Medium.

Overview

Welcome to part 3 of this series. If you did not follow through the previous parts, consider reading them before starting here.

  • In part 1, we learned how to add and configure Firebase to your React Native project.

  • In part 2, we learned how to add react-native-image-picker and learned how to set Firebase Storage rules.

  • In this part, we will learn step-by-step how to upload files from our device’s library and save them into a Firebase Storage bucket.

You can find the full source code in my Github.

Let’s jump right into it.

1. Add Firebase Storage

Start by adding the Firebase Storage module. This module depends on @react-native-firebase/app which you installed in part 1.

yarn add @react-native-firebase/storage

You need to add this new dependency for iOS.

cd ios
pod install

There is no additional configuration for Android.

You need to rebuild the apps in the simulators for iOS and Android. Kill your metro bundler and re-run the project.

npx react-native run-ios
npx react-native run-android

Add the following code to create a new storage instance in utils/index.js.

import storage from '@react-native-firebase/storage';

export const FireBaseStorage = storage();

2. Test Firebase Storage Integration With React Native

Time to test the integration of Firebase Storage with your React Native app.

Add the following code to components/UploadFile/index.js.

// ..
import { imagePickerOptions, FireBaseStorage } from '../../utils';
const UploadFile = () => {
  // ..
  return (
    <Container>

      {alert(JSON.stringify(FireBaseStorage))}

    </Container>
  );
};

In the above, you imported the FireBaseStorage and will render its output using the alert function.

Refresh your simulator. You should see a pop-up alert containing your Firebase Storage application details.

Alt Text

3. Upload files to Firebase Storage bucket

As seen in part 2, Image Picker returns a response object with a parameter that points to the location of the file in the device. This parameter is named uri in iOS and path in Android.

Following this observation, you will need a simple three-step process in order to upload files to a Firebase Storage bucket.

  • Get the local path for the file from the device: iOS vs. Android.

  • Attach a storage reference to the file for Firebase Storage.

  • Upload the file in the Firebase Storage bucket.

3.1. Get the local file source path

Start by adding the logic for step one. Add the following function in utils/index.js.

import { Platform } from 'react-native';

export const getFileLocalPath = response => {
  const { path, uri } = response;
  return Platform.OS === 'android' ? path : uri;
};

The above function destructures the path and uri parameters from the response object of Image Picker, then it returns one of these parameters depending on the platform (iOS or Android) using Platform from React Native.

You can now test the output of getFileLocalPath.

To do so, add getFileLocalPath to the imports in UploadFile/index.js.

import { imagePickerOptions, getFileLocalPath } from '../../utils';

Then, inside the uploadFile function add the following console log.

const uploadFile = () => {
  ImagePicker.launchImageLibrary(imagePickerOptions, response => {
    if (response.didCancel) {
      // ..
    } else {
      setImageURI({ uri: response.uri });
      console.log(getFileLocalPath(response));
    }
  });
};

Make sure you enable debug mode and then refresh the simulator. Then press the New Post button to add a new photo. You should see the file source logged in your Chrome Dev Console.

3.2. Attach a storage reference to the file

Your files are stored in the bucket. The files are presented in a hierarchical structure, just like the file system on your local hard disk.

By creating a reference to a file, your app gains access to it. More info on references in the Firebase docs.

Add the following function in utils/index.js.

export const createStorageReferenceToFile = response => {
  const { fileName } = response;
  return FireBaseStorage.ref(fileName);
};

The createStorageReferenceToFile function destructures the fileName from the Image Picker response. Then it returns a storage reference using FireBaseStorage.ref().

You can look at the output of the above function in the Chrome Dev Console. First, import createStorageReferenceToFile in UploadFile/index.js.

import { imagePickerOptions, createStorageReferenceToFile } from '../../utils';

Then, inside the uploadFile function add the following console log.

onst uploadFile = () => {
  ImagePicker.launchImageLibrary(imagePickerOptions, response => {
    if (response.didCancel) {
      // ..
    } else {
      setImageURI({ uri: response.uri });
      console.log(
        'My file storage reference is: ',
        createStorageReferenceToFile(response)
      );
    }
  });
};

Refresh the simulator and add a new photo. You should see the storage reference logged in your Chrome Dev Console.

Alt Text

3.3. Upload a file to the Firebase Storage bucket

This is the last step to send the file to your Firebase Storage bucket.
Add the following function in utils/index.js.

export const uploadFileToFireBase = imagePickerResponse => {
  const fileSource = getFileLocalPath(imagePickerResponse);
  const storageRef = createStorageReferenceToFile(imagePickerResponse);
  return storageRef.putFile(fileSource);
};

The above function incorporates the two previous functions (i.e. getFileLocalPath and createStorageReferenceToFile) to create the file path and the storage reference respectively.

Then, it sends the file to Firebase Storage using the putFile method. More on putFile in the official Firebase docs.

The final code in your utils/index.js should now look like this.

import { Platform } from 'react-native';

import storage from '@react-native-firebase/storage';

export const FireBaseStorage = storage();

export const imagePickerOptions = {
  noData: true,
};

const getFileLocalPath = response => {
  const { path, uri } = response;
  return Platform.OS === 'android' ? path : uri;
};

const createStorageReferenceToFile = response => {
  const { fileName } = response;
  return FireBaseStorage.ref(fileName);
};

export const uploadFileToFireBase = response => {
  const fileSource = getFileLocalPath(response);
  const storageRef = createStorageReferenceToFile(response);
  return storageRef.putFile(fileSource);
};

Import uploadFileToFireBase in UploadFile/index.js.

import { imagePickerOptions, uploadFileToFireBase } from '../../utils';

Then add the following lines of code inside the uploadFile function.

const uploadFile = () => {
  ImagePicker.launchImageLibrary(imagePickerOptions, response => {
    if (response.didCancel) {
      // ..
    } else {
      setImageURI({ uri: response.uri });
      // Remove this
      console.log(
        'My file storage reference is: ',
        createStorageReferenceToFile(response)
      );
      // Add this
      Promise.resolve(uploadFileToFireBase(response));

    }
  });
};

uploadFileToFirebase returns a JavaScript Promise through putFile. All we had to do is resolve it and return the result.

The final code in your UploadFile/index.js should now look like this.

import React, { useState } from 'react';
import { Button, StatusBar } from 'react-native';

import ImagePicker from 'react-native-image-picker';

import { imagePickerOptions, uploadFileToFireBase } from '../../utils';
import { Container, Picture, Skeleton, ProgressBar } from '../../styles';

const UploadFile = () => {
  const [imageURI, setImageURI] = useState(null);


  const uploadFile = () => {
    ImagePicker.launchImageLibrary(imagePickerOptions, imagePickerResponse => {
      const { didCancel, error } = imagePickerResponse;
      if (didCancel) {
        alert('Post canceled');
      } else if (error) {
        alert('An error occurred: ', error);
      } else {
        setImageURI({ uri: downloadURL });
        Promise.resolve(uploadFileToFireBase(imagePickerResponse))
      }
    });
  };

  return (
    <Container>
      <StatusBar barStyle="dark-content" />
      <Button title="New Post" onPress={uploadFile} color="green" />
      {imageURI && <Picture source={imageURI} />}
    </Container>
  );
};

export default UploadFile;

Time to test the file upload to Firebase Storage. Refresh your simulator.

Then press New Post to add a new photo.

Go to your Firebase Console. In the left tab bar, click on the Storage tab. You should see the photo saved in the Files tab (figure below).

Alt Text

Et Voila.

Conclusion

In this article, you added Firebase Storage and integrated it with your React Native app. You then followed a three-step process to get the local path of the file, created a storage reference for it, and uploaded it to Firebase Storage.

The next part is a super cool bonus. I will show you how to track the upload progress of your photo, display a progress bar on the screen, and retrieve the photo stored in your bucket. You can read part 4 in here.

Top comments (2)

Collapse
 
drazewski profile image
Łukasz Drążewski

Hi! Thank you for this series. It is very helpful for me. I have a small notice here. As you showed in part 2 the response objects from Android and iOS are different. I noticed that the response from iOS doesn't have fileName (in your example is equal null) so createStorageReferenceToFile method won't work. Maybe we could get the fileName from uri?

Collapse
 
kris profile image
kris • Edited

Exactly what I needed. Detailed stepwise implementation of uploading files to React Native Firebase Storage. The stepwise guide helps a lot and makes it easy to follow and implement as well. However, addition of more screenshots and demos of each coding step implementation would be highly appreciated.