Originally published in Medium.
Upload Files Using React Native and Firebase (Part 3) | by Younes Henni | Better Programming | Medium
Younes Henni ・ ・ 6 min read
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.
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
.
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).
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)
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?
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.