Danniel Hansel.

(03) — Blogs — Tutorial

Fetching data from Firestore

This quick guide shows you how to create a React custom hook to fetch data from Cloud Firestore.

Scroll ↓Fullstack Software Engineer — Dallas, TX
Photo by Tobias Fischer on Unsplash

This quick guide shows you how to fetch data from Cloud Firestore. Assuming you already have a collection with a list of documents.

Note: This guide will use Web version 9 (modular) - which is the latest version.

What we are going to do in this tutorial:

  • Understand how Event Sourcing & Event Streams work.
  • Understand how Snapshots work.
  • Create a React custom hook which listens to events from Firestore Database.
  • Render our data in our component.

If you don't have a project set up yet on Firebase, I have this quick guide to help you set it up.

💡 Once we've initialized our Firestore database, we will need it here.

Event Sourcing & Streams

In Event Sourcing, you'll typically replay all the events from the beginning of time from an Event Stream to get to the current state of your aggregate. In most occasions, you'll have a lifecycle to the stream that will eventually end but you could also have a stream that is never ending, something like products in a warehouse. The problem is what if we have thousands or millions of events that need to be replayed? This will create a very inefficient, time-consuming and slow process 😐 . This is where Snapshots come in.

Snapshots

A snapshot is a representation of state for your aggregate at a particular point in time or event. To get realtime updates with our Cloud Firestore database, we will need an onSnapshot() method which listens to a document. When you provide a callback in the initial call, it creates a document snapshot immediately with the current contents of the single document. Then, each time the contents change, another call updates the document snapshot. To listen to multiple documents in a collection, this method will listen to the results of a query which then creates a query snapshot.

React Custom Hook

In order fetch and render the most updated data from our Firestore Database onto our UI, we will need to create a custom hook. This hook's job is to listen to events from our database, record the state of the aggregate and store the state. By using onSnapshot() method, it attaches a listener for QuerySnapshot events in our Firebase. Note that although streams are never ending, this listener can be cancelled by calling the function that is returned when onShapshot() is called.

Explanation

We will store the snapshot in an array using the useState hook. To be able to detect changes, we will use the useEffect hook with our collection as dependency so that every document change in our collection gets hooked and stored in our state. The job of collection() method here is to get the CollectionReference instance that refers to the collection at the specified absolute path and returns the CollectionReference instance.

Code

Create a folder "hooks" inside src and create a file "useFirestore.js":

mkdir root/src/hooks
touch root/src/hooks/useFirestore.js

Stick this code in it:

import { useEffect, useState } from "react" // import the React hooks
import { onSnapshot, collection } from "firebase/firestore" // import the methods from firestore
import { firestoreDb } from "../config/firebase" // The reference to our Firestore database after we've initialized it.

export const useFirestore = col => {
  const [docs, setDocs] = useState([])

  useEffect(
    () =>
      onSnapshot(collection(firestoreDb, col), snapshot =>
        setDocs(snapshot.docs.map(doc => ({ ...doc.data(), id: doc.id })))
      ),
    [col]
  )

  return { docs }
}

Render your data

Create a file "Products.js" inside src/components.

touch src/components/Products.js

Then, copy this code in it:

import { useFirestore } from "../hooks/useFirestore" // Our hook we just created

const Products = () => {
  const { docs } = useFirestore("your-collection-name") // Our hook takes in the collectionName as parameter"

  return (
    <div>
      // ... add your own styling here
      <ul>
        {docs.map((product, index) => {
          return (
            <li key={index} className="flex my-2">
              <p>{index + 1}</p>
              <h1>{product.Name}</h1> // Grab the keys from your document fields
              <p>{product.Description}</p>
              <p>${product.Price}</p>
            </li>
          )
        })}
      </ul>
    </div>
  )
}
export default Products

Lets go ahead and run the app:

npm run dev

Voila! We can now fetch our data from Cloud Firestore database. 👏

While there is another option to fetch data from Firebase (like react-firebase-hooks), I chose to create my own customized hook that is understandable to me and works for me.

If you are interested to learn more on how to sort & update the data from Firestore or how to store & delete images from Firebase Storage, check out my other blog posts. Good luck!

Next page — (03)Blogs