DEV Community

Cover image for Fetching from Firestore Realtime Database
Clark Johnson
Clark Johnson

Posted on • Edited on

Fetching from Firestore Realtime Database

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 and the Firebase React Tutorial 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
Enter fullscreen mode Exit fullscreen mode

I included the necessary modules.

import app from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';
Enter fullscreen mode Exit fullscreen mode

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.

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"
};
Enter fullscreen mode Exit fullscreen mode

The class will connect to the services in the constructor.

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

}
export default Firebase;
Enter fullscreen mode Exit fullscreen mode

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.

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;
Enter fullscreen mode Exit fullscreen mode

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.

import React from 'react';

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

export default FirebaseContext;
Enter fullscreen mode Exit fullscreen mode

Then, I combined the exports for context and Firebase in src/Firebase/index.js

import FirebaseContext from './context';
import Firebase from './firebase';

export default Firebase;

export { FirebaseContext };
Enter fullscreen mode Exit fullscreen mode

My project's index.js wraps the <App /> component with the Context Provider.

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")
);
Enter fullscreen mode Exit fullscreen mode

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.

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

export default (props) => {
   ...
}
Enter fullscreen mode Exit fullscreen mode

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.

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]
  );
...

}
Enter fullscreen mode Exit fullscreen mode

** 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:

       <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>
Enter fullscreen mode Exit fullscreen mode

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!

Cover photo by Yuki Dog on Unsplash

Top comments (0)