Firebase Cloud Storage for React apps
Tags: webdev, javascript, react, firebase
Published: 2022-06-08 22:07:49

by [Mirth Briggs](https://blog.openreplay.com/authors/mirth-briggs)

Firebase v.9 SDK introduces a new API surface that follows a modular approach, resulting in a change in its services, one of which is Firebase Cloud Storage which allows us to upload and work with user-generated content like images and videos. 
In this tutorial, we will learn how to upload images/files to Firebase storage with version 9 web SDK.

To follow along with this tutorial, you should be familiar with React and have a google account. You should also have Node.js installed on your machine.

## Setting up Firestore
 
Before we can start using Firestore services, we need to create a project.

A Firebase project is like a container for our app. It lets us share data and analytics across platforms (e.g., Android, iOS, and web) so users have the same experience on any device they're on.
To add a project, make sure you're logged into your Google account, then navigate to [Firebase console](https://console.firebase.google.com/) and click **Add project** or **Create a project** button if this is your first time using Firebase. We should see a page like this:

![Add a project](https://blog.openreplay.com/static/e5bb2e68fa13748dfab34dae87d45d85/9ede6/image01.png)

Type in the project's name; for this tutorial, we'll call it **firebase-storage**. Then accept the Firebase terms and click **Continue**. We'll be prompted to enable Google Analytics; we don't need that in this tutorial, so let's turn it off. Click on **Create project** and wait for the project to be created. Once all the steps for adding a project are completed, we will be redirected to our project page:

![firebase-storage project page](https://blog.openreplay.com/static/f8375a8e9348fe60713adb6fb7ee1721/11012/image02.png)

On the sidebar of our project page, click on **Build** and then click on **Storage** to navigate to the Storage page:

![Storage page](https://blog.openreplay.com/static/95cdfdb18a3067f0de7f403f8726c43b/5aa16/image03.png)

Click the **Get started** button, and a prompt will appear asking if to Set up Cloud Storage in production or test mode.

![Get started](https://blog.openreplay.com/static/b4e24421c41d50f0b94d0a674ab89b39/70c6a/image04.png)

Choose **Start in test mode** and click **Next**. Then, on the next screen, click **Done.** Once the steps have been completed, an empty storage bucket will be created for us:

![A storage bucket, created](https://blog.openreplay.com/static/08da8cf44e76c963fda69d620979a55f/f80e3/image05.png)



## Setting up React and integrating with Firebase

First, create a new React app with the following command in the terminal:

```
$ npx create-react-app firebase-storage
```

In the above command, our app name is **firebase-storage**, but we can give it any other name. Next, navigate to the new app folder and install Firebase with the following commands:

```
$ cd firebase-storage
$ npm i firebase
```

To work with Firebase, we need to get the web configuration object and then use it to initialize Firebase in our react app.
On our Firebase project page, we should see something like this:

![Adding Firebase](https://blog.openreplay.com/static/304876144f1fad089774585ae90c275e/9ede6/image06.png)

Click on the web icon to configure our Firebase project for the web. We should see a page like this:

![Configuring the project](https://blog.openreplay.com/static/9f887974674866d0ebe9fb2733b242b5/9ede6/image07.png)

Give the web app a name. For this tutorial, we will call it **firebase-storage-app**. Click on the **Register app** button to move on to the next step, where our `firebaseConfig` object is revealed to us:

![Configuration object](https://blog.openreplay.com/static/d8d158d99af49dcb44f858ebe4cf35eb/332ff/image08.png)

Copy the firebase config object to the clipboard as we will need it later on to initialize Firebase. Then click on the **Continue to console** button to complete the process.

Now, let’s initialize Firebase and Firebase storage so that we can start using them in our app. In the `src` directory of the React app we created earlier, create a `firebase.js` file and add the following lines of code:

```javascript
// src/firebase.js
import { initializeApp } from "firebase/app"
import { getStorage } from "firebase/storage"

const firebaseConfig = {
  apiKey: "API_KEY",
  authDomain: "AUTH_DOMAIN",
  projectId: "PROJECT_ID",
  storageBucket: "STORAGE_BUCKET",
  messagingSenderId: "MESSAGING_SENDER_ID",
  appId: "APP_ID"
}

// Initialize Firebase and cloud storage
export const app = initializeApp(firebaseConfig)
export const storage = getStorage(app)
```

Replace the `firebaseConfig` object in the above code with the one we copied earlier.

## Upload and Read Files/Images in Firebase storage

Before we can start using the ready-to-use function provided by Firebase for working the cloud storage, let's first create a simple React app that will let us upload files. The app will contain a form for uploading files and a button for submitting them.

In the **src** directory, modify the `App.js` file to look like the following: 

```javascript
// src/App.js
import './App.css'

function App() {
  return (
    <div className="app" name='upload_file'>
      <form className='app__form'>
        <input type='file' />
        <button type='submit'>Upload</button>
      </form>
    </div>
  )
}

export default App
```

Now let’s add some styling to our app to make it look better. Modify the `App.css` file to look like the following:

```
// src/App.css
.app{
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
}
.app__form{
  display: grid;
  grid-gap: 10px;
}
```

When we start the development server with `$ npm start`, this is what the app should look like:

![Running our app](https://blog.openreplay.com/static/2613ff79648703d2a446e0322ce43e39/1cb32/image09.png)


## Open Source Session Replay

_[OpenReplay](https://github.com/openreplay/openreplay) is an open-source, session replay suite that lets you see what users do on your web app, helping you troubleshoot issues faster. OpenReplay is self-hosted for full control over your data._

![replayer.png](https://raw.githubusercontent.com/openreplay/openreplay/main/static/replayer.png)

_Start enjoying your debugging experience - [start using OpenReplay for free](https://github.com/openreplay/openreplay)._



## Uploading and reading files

To upload an input file to Firebase cloud storage, we can either use the `uploadBytes` or `uploadBytesResumable` functions. They both achieve the same result, but the difference is that using `uploadBytesResumable` will allow us to monitor our files' progress and carry out specific actions like pausing or canceling the uploading of the file. At the same time, `uploadBytes` doesn't have that functionality.

Firebase also provides a function for getting the URL of an uploaded file, `getDownloadURL`. In this section, we will learn how to use the `uploadBytes` function to upload our files and read them with `getDownloadURL`. Then, later on we will look at how we can monitor the progress of uploaded files using the `uploadBytesResumable` function.

In the `App.js` file, add the following imports:

```javascript
// src/App.js
import { storage } from './firebase'
import { ref, getDownloadURL, uploadBytes } from "firebase/storage"
```

Next, add the following function before the return statement in the `App` component:

```javascript
// src/App.js
const handleSubmit = (e) => {
  e.preventDefault()
  const file = e.target[0]?.files[0]

  if (!file) return null;
  const storageRef = ref(storage, `files/${file.name}`)
  uploadBytes(storageRef, file)
  .then((snapshot) => {
    e.target[0].value = ''
    getDownloadURL(snapshot.ref).then((downloadURL) => {
      console.log(downloadURL)
    })
  })
}
```

In the above code, we are getting the file input with `e.target[0]?.files[0]`. With the  `if` statement, we return `null` if no file is present, but if there is, we create a reference to the Firebase project storage we want to upload our file to using the `ref` function. The `ref` function receives the storage instance initialized in our `firebase.js` file as its first parameter and a path we want uploaded files to reside in as a second parameter (optional).

We upload the file by calling the `uploadBytes` function, which takes the reference and the file to be uploaded as a parameter. This function returns a promise. On a fulfilled promise, we empty the file input and then download the URL of the uploaded file by using the `getDownloadURL` function, which takes the file reference as a parameter.

Next, we need to call the above function when the form is submitted. We can do that by modifying the opening tag of the **upload_file** form:

```javascript
// src/App.js
<form className='app__form' name='upload_file' onSubmit={handleSubmit}>
```

Now in our React app, when we choose a file and click the **Upload file** button, the file will be uploaded to cloud storage, and the URL to access the file will be logged in to the browser console. If we are working with a database, we can then save the URL in the database rather than logging it to the console.

Aside from uploading input files which is a JavaScript [File](https://developer.mozilla.org/en-US/docs/Web/API/File) type, using `uploadBytes` we can also upload [Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob) and [Uint8Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array). Depending on the use-case, our file might also be in `base64`, `base64url`, or `data_url` format for that we can use the `uploadString` function which is similar to using `uploadBytes`, but it receives the file form as its third parameter. You can check how `uploadString` works [here](https://firebase.google.com/docs/storage/web/upload-files#upload_from_a_string).

## Monitor Upload status while uploading

In cases where we are uploading a large file that will take some time before it completes uploading, we might want to monitor the upload progress of the file through a progress bar. For that, we will use the `uploadBytesResumable` function. 
Now, let's see how to use this function to display the progress of uploaded files on a progress bar and also get the download URL.

First, in the **App.js** file add the following import:

```javascript
// src/App.js
import { useState } from 'react';
import { uploadBytesResumable } from 'firebase/storage';
```

Next, add the following state to the `App` component:

```javascript
// src/App.js
const [progressPercent, setProgressPercent] = useState(0)
```

Next, modify the handleSubmit function in the `App` component to look like this:

```javascript
// src/App.js
const handleSubmit = async (e) => {
  e.preventDefault()
  const file = e.target[0]?.files[0]

  if (!file) return null;
  const storageRef = ref(storage, `files/${file.name}`)
  const uploadTask = uploadBytesResumable(storageRef, file)

  uploadTask.on("state_changed",
    (snapshot) => {
      const progress = Math.round((snapshot.bytesTransferred / snapshot.totalBytes) * 100)
      setProgressPercent(progress)
    },
    (error) => {
      alert(error)
    },
    () => {
      e.target[0].value = ''
      getDownloadURL(storageRef).then((downloadURL) => {
        console.log(downloadURL)
      })
    }
  )
} 
```

In the above code, after passing the reference and the file to upload as a parameter to the `uploadBytesResumable` function call, we call the `on()` method from the object returned, which listens to events of the ongoing upload. Above, we are listening to the **state_changed** event. Events have three callback functions **next**, **error,** and **completed**. These are the callbacks we passed in the `on()` method 

The **next** callback listens to progress/state changes of the upload. It makes available a snapshot object with properties that we are using to calculate the progress of the upload. 
The **error** callback is used to handle errors. Right now, our code is just alerting the error, but there is more to handling errors; we will look more into this later in this tutorial. The last callback runs when an upload has been completed, and that's where we are resetting the input and getting the download URL.

We can also manage uploads like pause, resume, and cancel uploads using the `pause()`, `resume()`, and `cancel()` methods which can be accessed in the object returned from calling the `uploadBytesResumable` function something like this:

```javascript
const uploadTask = uploadBytesResumable(storageRef, file);

// Pause the upload
uploadTask.pause();

// Resume the upload
uploadTask.resume();

// Cancel the upload
uploadTask.cancel();
```

Finally, add the line of code after the closing form tag (`</form>`) in the return statement:

```javascript
// src/App.js
<progress value={progressPercent} max="100"/>
```

In the above code, we are setting the value of the progress bar equal to the `progressPercent` state, which we are setting in the first observer of the `uploadTask.on` method, which runs every time the upload state changes.

When we go over to our React app and try to upload a large file like a video, we will notice the progress in the progress bar.

![Progress bar](https://blog.openreplay.com/static/e285b38f1f5dafb935fb8d3791140db2/9c46d/image10.png)

With this, we can now upload to cloud storage and also monitor our progress. What about the error handle?. To handle errors that might occur upon uploading, we can use the code available in the error object to show custom error messages. For example, to handle an error caused by canceling an upload, the error callback will look something like this:

```javascript
(error) => {   
  switch (error.code) {
    case 'storage/canceled':
      alert('Upload has been canceled')
      break;
  }
}
```

You can view the complete list of error codes [here](https://firebase.google.com/docs/storage/web/handle-errors#handle_error_messages).

## Conclusion

Using Firebase Cloud storage is pretty straightforward. With a few lines of code, we can upload and download files and monitor uploaded files' progress with the ready-to-use function provided in the Firebase SDK. Hopefully, at this point, you should be able to work with Firebase cloud storage in your app.


[![newsletter](https://blog.openreplay.com/static/e6b18eda7a327511296a2f27692f9c70/e9957/newsletter.png)](https://newsletter.openreplay.com/)