Fetching from Firestore Realtime Database
Tags: javascript, react
Published: 2020-07-12 23:06:39

This week I was tasked with learning about Firebase and setting up an application to interact with the Firestore Realtime Database for storage.

I don't want to repeat all the details of the experience because I basically implemented the instructions found in the [Firebase documentation](https://firebase.google.com/docs/database/web/read-and-write) and the [Firebase React Tutorial](https://www.robinwieruch.de/complete-firebase-authentication-react-tutorial#manage-users-with-firebases-realtime-database-in-react) by Robin Weiruch.

This is how I implemented using the fetch API to retrieve the data.

## 1. Connect to the Firebase Services
Implementing the connection to Firebase services and the functions necessary to retrieve and mutate the data can be neatly encapsulated in a class.  I created mine in the file `/src/Firebase/firebase.js`.

Be sure to add the Firebase npm modules.
```
yarn add Firebase
```
I included the necessary modules.

```javascript
import app from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';
```
The configuration variable details were provided when I set up my Firebase project.  I just copied and pasted mine.  I've included it below, with a couple of specifics missing.

```javascript
var firebaseConfig = {
    apiKey: "--------------------------------",
    authDomain: "myproject.firebaseapp.com",
    databaseURL: "https://myproject.firebaseio.com",
    projectId: "myproject",
    storageBucket: "myproject.appspot.com",
    messagingSenderId: "748127105525",
    appId: "1:748127105525:web:983360bf4adfabfa3bf0bc",
    measurementId: "G-6ZWGLLZQ1Y"
};
```
The class will connect to the services in the constructor.

```javascript
class Firebase {
    constructor() {
        app.initializeApp(firebaseConfig);
        this.auth = app.auth();
        this.db = app.firestore();
    }
...

}
export default Firebase;
```
## 2. Code the Read Method
Reading and writing are handled through the methods provided in the Firebase library.  For example, reading from the **users** collection can be done using `app.firestore().collection("users").get()`.  Writing can be done using similar methods, such as `app.firestore().collection("users").doc(_key).set(_profileObject)`. 

As you might expect, these methods are executed asynchronously.  I wrapped the read method so that I could include a callback for handling the data once it's retrieved.
```javascript
class Firebase {
    constructor() {
        app.initializeApp(firebaseConfig);
        this.auth = app.auth();
        this.db = app.firestore();
    }
...

    doGetAllUsers = (callback) => {
        this.db
            .collection("users")
            .get()
            .then(callback)
    }
...

}
export default Firebase;
```
## 3. Create a Context for Firebase Services
To make use of the Firebase connection across my application, I included **useContext**.

I created the file **src/Firebase/context.js** in my Firebase directory.
```javascript
import React from 'react';

const FirebaseContext = React.createContext(null);
FirebaseContext.displayName = "Firebase"

export default FirebaseContext;
```

Then, I combined the exports for context and Firebase in **src/Firebase/index.js** 
```javascript
import FirebaseContext from './context';
import Firebase from './firebase';

export default Firebase;

export { FirebaseContext };
```

My project's **index.js** wraps the `<App />` component with the Context Provider. 
```javascript
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import Firebase, { FirebaseContext } from './components/Firebase';

ReactDOM.render(
    <FirebaseContext.Provider value={new Firebase()}>
      <App />
    </FirebaseContext.Provider>,
  document.getElementById("root")
);
```
## 4. Use React Hooks to Store the Data 

Now that the Firebase class is ready to go, let's make use of it within a React component.
 
I included the appropriate React hooks tools as well as the **FirebaseContext**.  

```javascript
import React, { useContext, useEffect, useState } from "react";
import { FirebaseContext } from "../../components/Firebase";

export default (props) => {
   ...
}
```

I assigned the identifier **firebase** to the context for my Firebase class.  This allows me to access the connected Firebase services within my component.

Then I created a state variable **docs** to hold the **users** collection records.

Finally, I invoked the `firebase.doGetAllUsers()` method I wrote earlier, passing it a callback function to store the data in this component's state.

```javascript
export default (props) => {
  const firebase = useContext(FirebaseContext);
  const [docs, setDocs] = useState([]);

  // Pass a callback to handle the data.  
  useEffect(
    () =>
      firebaseb.doGetAllUsers((snapShot) => {
        const tempDocs = [];
        snapShot.forEach((doc) => {
          tempDocs.push(doc.data());
        });
        setDocs([...tempDocs]);
      }),
    [fb]
  );
...

}
```

** It's important to note that the array `[fb]` was passed to **useEffect** as the second parameter, which is set call the function only when certain values have changed.  In this case, the value of `fb` won't change, and the function will only be executed when the component mounts.
 
That should do it.  The data from the **users** collection will now be stored in the state variable and can be rendered by the component.  For example:
```javascript
       <div>
          <h2>Users</h2>
          {docs.length > 0 ? (
            docs.map((doc, i) => (
              <div key={i}>
                <p>
                  {doc.firstName} {doc.lastName}, {doc.city}
                </p>
              </div>
            ))
          ) : (
              <div>
                <p>No users found.</p>
              </div>
            )}
       </div>
```

This is what I learned.  I hope this helps others attempting to stand up a React app with Firestore Realtime Database.  As this was my first implementation, I welcome any suggestions on improvement.

Happy coding!

<span>Cover photo by <a href="https://unsplash.com/@adventure_yuki?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Yuki Dog</a> on <a href="https://unsplash.com/s/photos/fetch?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></span>