Using React Native you can build a variety of app screens that are cross-platform using JavaScript as the main programming language. One such app screen feature is uploading photos which is quite a common feature in social media apps. Uploading photos to Firebase Storage is a common practice in React Native apps that have backend integration with Firebase, such as our React Native templates. In this tutorial, let’s build a demo app in which you are going to create a simple screen that allows you to pick an image from the app running on the device, using an image picker and upload it to the Firebase Cloud Storage. The second screen is going to display these images.
Getting started
Start by creating a new react native project. Run the following command from a terminal window. After the project directory is created, navigate inside it and install the required dependencies.
npx react-native init uploadStorageDemo cd uploadStorageDemo yarn add react-native-progress react-native-image-picker
Do note that this tutorial uses a react-native version above 0.60.x
. If you are using a version below that, make sure to seek guidance on how to link native binaries for the libraries mentioned in this tutorial. To follow instructions on how to configure react-native-image-picker
for each mobile platform, I highly recommend you to go through the official docs here. For iOS, make sure to install pods.
cd ios/ && pod install # after pods install cd ..
Create an upload screen
The current demo app is going to contain one screen that will help the user to select an image from the device’s photo library. Create a file called UploadScreen.js
inside src/screens/
directory and the following mock snippet for now.
import * as React from 'react'; import { Text, View } from 'react-native'; export default function UploadScreen() { return ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> <Text>Upload!</Text> </View> ); }
Open App.js
file and import the AppTabs
.
import React from 'react'; import { StatusBar } from 'react-native'; import UploadScreen from './src/screens/UploadScreen'; const App = () => { return ( <> <StatusBar barStyle="dark-content" /> <UploadScreen /> </> ); }; export default App;
Now, go back to the terminal window and build the react native app for the platform or the OS you wish to run it on.
# for iOS npx react-native run-ios # for Android npx react-native run-android
I am going to use the iOS simulator for this demo. Open the app to the simulator and you are going to see the following output.
Create a new Firebase Project
To access the Firebase credentials for each mobile OS platform and configure them to use the Firebase SDK, create a new Firebase project from the Firebase console, or if you already have access to a project in your console, you can skip this step. Create a new project as shown below. Add the details of your Firebase project. Click the button “Create project”, and you should be redirected to the dashboard screen. You should see your newly-created project on that dashboard.
Add Firebase SDK to React Native app
Using react-native-firebase
version 5 or below, since it was a monorepo, all Firebase dependencies were available from a single module to use in a React Native app. However, with version 6 you have to install dependencies based on Firebase features that you want to use. For example, in the current app, to use storage, you are going to install the core app package as well as storage package. As said that the core module @react-native-firebase/app
is always required. Open a terminal window to install these dependencies.
yarn add @react-native-firebase/app @react-native-firebase/storage
Add Firebase credentials to your iOS app
Firebase provides a GoogleService-Info.plist
file that contains all the API keys as well as other credentials needed for iOS devices to authenticate the correct Firebase project. To access these credentials, go to back to the “Firebase console”, and from the dashboard screen of your Firebase project, open “Project settings” from the side menu. Go to the “Your apps” section and click on the icon iOS
to select the platform. Enter the application details and click on the “Register app”. Then download the GoogleService-Info.plist
file, as shown below. Open Xcode, and then open the /ios/uploadStorageDemo.xcodeproj
file. Right-click on the project name and choose the Add Files option—then select the appropriate file to add to this project. Next, open ios/uploadStorageDemo/AppDelegate.m
and add the following header.
#import <Firebase.h>
Within the didFinishLaunchingWithOptions
method, add the following configure method.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { if ([FIRApp defaultApp] == nil) { [FIRApp configure]; }
Go back to the terminal window to install pods.
cd ios/ && pod install # after pods are installed cd ..
Make sure you build the iOS app before running it. Open
npx react-native run-ios
Add Firebase credentials to your Android app
For Android apps, Firebase provides a google-services.json
file that contains all the API keys as well as other credentials needed for Android devices to authenticate the correct Firebase project. Go to the “Your apps” section and click on the icon Android
to select the platform. Download the google-services.json
file. Now copy the downloaded JSON file in React Native project at the following location: /android/app/google-services.json
. Open your android/build.gradle
file to add the following snippet.
dependencies { // ... classpath 'com.google.gms:google-services:4.2.0' }
Next, open android/app/build.gradle
file, and at the very bottom of this file, add the following snippet.
apply plugin: 'com.google.gms.google-services'
Lastly, make sure you build the Android app.
npx react-native run-android
Using React Native Image Picker
In this section, let us start building the app. Start by opening the file UploadScreen.js
and import the following statements.
import React, { useState } from 'react'; import { View, SafeAreaView, Text, TouchableOpacity, StyleSheet, Platform, Alert, Image } from 'react-native'; import ImagePicker from 'react-native-image-picker'; import storage from '@react-native-firebase/storage'; import * as Progress from 'react-native-progress';
Inside the function component UploadScreen
create three state variables. The first, image
is going to be used to store the URI of the source of the image. The same URI will be then used to display the image picked by the user and to upload the image to the Firebase cloud storage. The second state variable is uploading
that is going to be false
default. This is going to keep track of whether the image is uploading to the cloud storage or not. The third variable transferred
is going to track the progress of the image being upload.
export default function UploadScreen() { const [image, setImage] = useState(null); const [uploading, setUploading] = useState(false); const [transferred, setTransferred] = useState(0); //... }
Add a helper method called selectImage
that is going to use the react-native-image-picker
to select an image from the device’s library and display the image picker itself. Also, define an options
object to set properties like maximum width and height as well as a default path. This options
object is going to be passed as the first parameter in ImagePicker.showPicker()
method that is going to return a callback which sends the response
object. Using this callback, the path of the image state variable can be set. You can find the complete set of options to pass in the official docs here.
const selectImage = () => { const options = { maxWidth: 2000, maxHeight: 2000, storageOptions: { skipBackup: true, path: 'images' } }; ImagePicker.showImagePicker(options, response => { if (response.didCancel) { console.log('User cancelled image picker'); } else if (response.error) { console.log('ImagePicker Error: ', response.error); } else if (response.customButton) { console.log('User tapped custom button: ', response.customButton); } else { const source = { uri: response.uri }; console.log(source); setImage(source); } }); };
Define another helper method called uploadImage
that is going to upload the image to the cloud storage. This method is going to be asynchronous by default so let us async-await
syntax. Also, when this method triggers, update the value of uploading
to true and transferred
to 0 to track the progress of the image being upload to the storage. Using storage
from Firebase you can trigger the image upload. It is important to note that the filename
has to be passed as a reference as well as the image URI using putFile
in the order described below. After the image has uploaded to the storage, display an alert method using react native component Alert
and set state variables to default as shown below.
const uploadImage = async () => { const { uri } = image; const filename = uri.substring(uri.lastIndexOf('/') + 1); const uploadUri = Platform.OS === 'ios' ? uri.replace('file://', '') : uri; setUploading(true); setTransferred(0); const task = storage() .ref(filename) .putFile(uploadUri); // set progress state task.on('state_changed', snapshot => { setTransferred( Math.round(snapshot.bytesTransferred / snapshot.totalBytes) * 10000 ); }); try { await task; } catch (e) { console.error(e); } setUploading(false); Alert.alert( 'Photo uploaded!', 'Your photo has been uploaded to Firebase Cloud Storage!' ); setImage(null); };
Here is the complete JSX returned from this functional component. The progress that you are going to show in the app is going to be in the form of a bar.
export default function UploadScreen() { //... rest of the code return ( <SafeAreaView style={styles.container}> <TouchableOpacity style={styles.selectButton} onPress={selectImage}> <Text style={styles.buttonText}>Pick an image</Text> </TouchableOpacity> <View style={styles.imageContainer}> {image !== null ? ( <Image source={{ uri: image.uri }} style={styles.imageBox} /> ) : null} {uploading ? ( <View style={styles.progressBarContainer}> <Progress.Bar progress={transferred} width={300} /> </View> ) : ( <TouchableOpacity style={styles.uploadButton} onPress={uploadImage}> <Text style={styles.buttonText}>Upload image</Text> </TouchableOpacity> )} </View> </SafeAreaView> ); }
Here are the complete styles for the above component.
const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', backgroundColor: '#bbded6' }, selectButton: { borderRadius: 5, width: 150, height: 50, backgroundColor: '#8ac6d1', alignItems: 'center', justifyContent: 'center' }, uploadButton: { borderRadius: 5, width: 150, height: 50, backgroundColor: '#ffb6b9', alignItems: 'center', justifyContent: 'center', marginTop: 20 }, buttonText: { color: 'white', fontSize: 18, fontWeight: 'bold' }, imageContainer: { marginTop: 30, marginBottom: 50, alignItems: 'center' }, progressBarContainer: { marginTop: 20 }, imageBox: { width: 300, height: 300 } });
Here is the output you are going to get. To verify that the image is stored in the cloud storage, go back to the Firebase console dashboard and go to the storage section.
Conclusion
Thanks for following up this tutorial. Using react-native-firebase
version 6 brings benefits like less configuration and focus more on developing the app. Do refer the docs of react-native-progress
for more information on customizing the progress bar. You can also check this interesting website on cloud storage reviews.
Next Steps
Now that you have learned about resources to learn React Native development, here are some other topics you can look into
- Firebase — Push notifications | Firebase storage
- How To in React Native — WebView | Gradient| Camera| Adding GIF| Google Maps | Redux | Debugging | Hooks| Dark mode | Deep-link | GraphQL | AsyncStorage | Offline |Chart | Walkthrough | Geolocation | Tinder swipe | App icon | REST API
- Payments — Apple Pay | Stripe
- Authentication — Google Login| Facebook login | Phone Auth |
- Best Resource – App idea | Podcast | Newsletter| App template
If you need a base to start your next React Native app, you can make your next awesome app using many React Native template.
3 Comments
BAW · June 3, 2020 at 9:33 am
Thanks so much! Most concise tutorial i’ve found! Worked a treat!
Keo · November 17, 2020 at 9:57 pm
Hello!
Do you know if I would be able to do this using Expo? I am trying to figure out a way to upload files to firebase using expo. Thanks
Florian Marcu · November 17, 2020 at 11:27 pm
Not possible unfortunately, we highly recommend against Expo, especially if you use Firebase.