Hey there! In this article, we are going to take a very simple React / Redux app and connect it to Google’s new Cloud database: Cloud Firestore. This app will do three very simple things:

Ask Google a question (make a request to Firestore) Listen to Google’s answer (store the response from Firestore in a Redux container) Declare Google’s answer to the world! (connect the Redux container to a React front-end)

Note: If you are like me and just click on these blog posts to find the source repo, here you go: https://github.com/borkjt9/firestore-react-redux. Just remember that the application will not run correctly without inserting your own Firebase credentials in the config file.

Side Note: At the start of each section, I link to a different branch in the source repo. If you are only interested in a specific section of this article or want to just skip ahead, clone the linked branch and you can follow along with the tutorial from there.

Other Side Note: In some of the steps below, I ask you to copy and paste large amounts of code. I do this because, in these instances, I find the code is easier to understand when you can see the entire picture.

Ok then. Let’s get started!

Step 1: The Set-Up

Starting Point: https://github.com/borkjt9/firestore-react-redux/tree/step-one

Because there are already a million tutorials out there to help you create a React / Redux application, I am going to make an executive decision (hey it’s my post) and fast forward through the explanation of how to set up a React / Redux application (If you need a refresher, this is a good one).

This means I have already done the boring bits for you and have created a ‘Hello World’ React / Redux app. This app will be the launching point for everything we do going forward so open your favorite CLI and clone the Starting Point repository now.

Your newly cloned directory should have the below file structure:

hello-firestore

├── README.md

├── node_modules

├── package.json

├── .gitignore

├── public

│ ├── favicon.ico

│ ├── index.html

│ └── manifest.json

└── src

├── App.js

├── App.css

├── App.test.js

├── constants.js

├── index.css

├── index.js

├── logo.svg

├── redux

├── actions

├── reducers

├── reducers.js

└── store.js

└── serviceWorker.js

Take a minute to look through the repository. If some of the code looks familiar to you, it’s because I lifted most of it directly from Facebook’s wonderful create-react-app tutorial. If you haven’t seen this repository before, take fifteen minutes to read the create-react-app READme file (Facebook does a much better job explaining their code than I ever could).

But I have made a few small changes that you should be aware of:

I added a constants.js file. Whenever I write applications that contains a large number of static string references, I like to store the references in a central location. Doing so not only decreases the risk of bugs but also makes it much easier to modify your codebase in the future (for example if the name of your database changes). I added a redux store! This Redux store contains a single action. Later on we will modify this action to help us fetch responses from our Firestore database. Our store also contains a single reducer which will eventually store the response received from Firebase. I connected the ‘App’ component to our redux store. In App.js I have imported the react-redux library and have used its connect function to map our store’s state to App’s props. I have also updated the JSX to display a button that dispatches our ‘fetch’ action and displays the response.

To check that everything works correctly (which is a good habit to get into before making changes to any codebase), navigate to the newly cloned ‘hello-firestore’ directory in your CLI. Run the following commands:

npm install

npm start

If you have not seen the npm command before, read up on it here: https://www.npmjs.com. Basically, npm is a wildly popular javascript package manager that makes it really easy to install and incorporate third party libraries into your applications.

After running npm start , your default browser automatically should have been directed to localhost:3000/home. If this did not occur, open your browser and do so manually now. If everything worked correctly, you should see the following page in your browser.

Please ignore my ab workout vid bookmarks

Does your browser look the same as mine? Great! Try clicking the green button that says Get Firestore Answer. Some placeholder text should appear on the screen. Later we are going to use this button to make a request to Firestore and display its response instead.

But before we can do that, we have to set up our Firestore database. Let’s get to it.

Step 2: Create your very first Firestore database

Starting Point: https://github.com/borkjt9/firestore-react-redux/tree/step-two

A quick word before we dive into this section: a lot of what we are about to do is taken directly from Firebase’s own quickstart guide. Just as how I mentioned above with Facebook’s create-react-app, Google does a much better job explaining their product than I ever could. So if you want to skip this section and follow along with them instead you won’t hurt my feelings one bit.

But if you have decided to stick with me great! Let’s learn a little bit about Firestore. While it may seem super advanced at first glance, Firestore at its core is a traditional NoSQL database. In layman’s terms, this means that there are no rows or tables in Firestore. Rather, data is stored in documents which are organized into collections. Storing data in documents is very similar to storing data in JSON objects. A document contains fields (think keys) which point to values. Values support a variety of data types: boolean, number, string, geo point, binary blob, and timestamp, as well as more complex types like arrays, objects, and even subcollections (but don’t worry about subcollections for now).

Ok enough backstory. Time to create our database!

Open the Firebase Console and create a new project. Name it whatever you want. For consistency, I named mine hello-firestore.

In the Database section, click Get Started for Cloud Firestore. You will be prompted to start in either Test Mode or Locked Mode. Select Test Mode and click Enable. Test Mode is fine when starting a new project, but note that it allows anyone to read and overwrite your Firestore data. Please remember to never use Test Mode in Production. Ever.

I REPEAT. DO NOT USE TEST MODE IN PRODUCTION!

Click Add Collection. Name your collection questions. The name of your collection is important because we will need to query it later on.

Click Next. A screen will pop up that asks you to create your first document. The document ID field is optional, and if you don’t add one Firestore will automatically generate one for you. I usually elect to create my own document IDs because they can be helpful if you ever need to query for specific documents (for example if you are obtaining data related to a specific user). So let’s give our document a name. To make everything consistent, let’s name it hello-firestore.

Add a field called response. Select type string. For a value, write any response you want. This response will later be displayed in our application in lieu of the placeholder we saw Step 1. I set mine to ‘Hey! I’m awesome!’ because positive self-talk is important.

Click Save. That’s it! You have just created your very first Firestore database!

Step 3: Initialize Firestore in your application

Starting Point: https://github.com/borkjt9/firestore-react-redux/tree/step-three

Now that our database is set up, we need to pull in the credentials into our app so that it can connect to your Firebase Project.

Stay in the Firebase Console. Click the gear icon in the Project Overview section and select Project Settings. In the Your Apps section (at the bottom of Project Settings), click the link for Web (symbol should look like </>). A popup will appear that displays a config object. These are your credentials. Save them somewhere you will remember. We will need them very shortly.

Back in your CLI, make sure you are still in your hello-firestore directory. Before we write any code (we’re soooo close), we need to add the Firebase SDK (short for Software Development Kit) to our application. You can read up on them here if you are so inclined (it has been open-sourced by Google). Run the following command in your CLI:

npm install --save firebase

Now let’s get coding! In your src folder, create a sub-folder called firestore and add a config.js file to it. This config file is where we will initialize our instance of Firestore.

In config.js, import both Firebase and Cloud Firestore at the top of the file. The dual imports may seem redundant, but both are needed to add Firestore to your application.

import firebase from 'firebase/app';

import 'firebase/firestore';

Retrieve your credentials from wherever you saved them a minute ago. Copy the below code and fill in the blanks with your app’s information.

// Below keys are found in Firebase Console -> Project Overview ->

Project Settings -> General const config = {

apiKey: '### FIREBASE API KEY ###',

authDomain: '### FIREBASE AUTH DOMAIN ###',

projectId: '### CLOUD FIRESTORE PROJECT ID ###'

};

firebase.initializeApp(config);

By calling the initializeApp function, from this point onward every time we reference a Firebase service in our application it will have access to the Firebase project we set up in Step 2. Think of your Firebase Project as being surrounded by a gate, and your credentials open the gate.

It’s important to note that while these credentials are unique, they are non-secret. This means that as long as you set up appropriate security rules, your project will be secure even if these keys become exposed. Visit Understand Firebase Projects to learn more about the mechanics behind these credentials.

All that is left is to set a default export for our config module. Since we are only using Firestore in this tutorial, let’s set an instance of Firestore as the default. This Firestore instance will con all the methods to set and get data from our Firestore database.

export default () => firebase.firestore();

Step 4: Make a request to your Firestore database

Starting Point: https://github.com/borkjt9/firestore-react-redux/tree/firestore-redux

Did writing that code tire you out? Let’s take a small break. Before we make any requests to our database, it’s time for some more background information on Firestore. Specifically on how Firestore queries work.

Firestore is set up with a really powerful querying engine. One of the coolest features of Firestore is that the time it takes to run a query is directly proportional to the number of results of the query, not the number of documents that are queried. This means that it doesn’t matter whether you are searching through a collection of 10 documents or 10,000; both queries will cost the same amount of time and resources.

Obviously, this has really significant implications for running Firestore applications at scale. It also means that Firestore queries work a little differently than what you may be used to.

As such, there are some rules you should take note of whenever querying Firestore:

Queries can be made on either collections or documents. You can only query one collection at a time, but you can query that collection for multiple documents. You can retrieve multiple documents in a collection by using simple and compound queries. Queries for multiple documents will be returned in ascending order by Document ID by default, but you can also create custom orders. Query conditions take the form of basic equality operations: equal to, less than, and greater than. Even if a document you are searching for does not exist, the request will still return a promise that resolves. To secure your data, you must add Firebase Security Rules.

If you want even more detail on how Firestore queries work, check out this great video put out by the Firestore team.

Ok. Back to coding.

Navigate to your firestore folder and create a file called answers.js. Answers.js will house the function we will use to make requests to Firestore.

Just to make sure we are still on the same page, your folder structure should now look like the following:

hello-firestore

├── README.md

├── node_modules

├── package.json

├── .gitignore

├── public

│ ├── favicon.ico

│ ├── index.html

│ └── manifest.json

└── src

├── App.js

├── App.css

├── App.test.js

├── constants.js

├── index.css

├── index.js

├── logo.svg

├── redux

├── actions

├── reducers

├── reducers.js

└── store.js

├── firestore

├── config.js

└── answers.js

└── serviceWorker.js

In answer.js, at the top of the file import the Firestore instance you created in Step 3 from config.js.

import FirestoreDB from '../config';

You can name the imported variable whatever you want, but remember that it will refer to a Firestore instance contains all the methods you need to query data from firestore. I named mine FirestoreDB.

Next, update constants.js to include a new export called COLLECTION_QUESTIONS. We will use this variable as a reference to the Collection we created in Step 2.

export const COLLECTION_QUESTIONS = 'questions';

Now import it at the top of answer.js.

import { COLLECTION_QUESTIONS } from ‘../constants’

Last, copy and paste the below FetchAnswer function into answer.js.

/**

* fetchAnswer - makes requests to Firestore

* @param {String} question name of the document we are querying for

* @return {Promise} response from Firestore db

*/

function fetchAnswer(question) {

// Calls to Firestore return a promise.

// If no document exists, the promise will still resolve.

return FirestoreDB().collection(COLLECTION_QUESTIONS)

.doc(question).get() //get() is Firestore’s main method to retrieve data

.then((doc) => {

// check if the document exists

if (doc.exists) {

const { response } = doc.data();

return response;

} else {

throw new Error('No Such Document');

}

})

.catch(error => error);

} export default fetchAnswer;

Some key points about the fetchAnswer:

FetchAnswer accepts a single parameter question. Question should always be of type string and will refer to the document ID we want to query. FetchAnswer searches through our Firestore database’s questions collection and determines whether a document exists via FirestoreDB’s get() method. FirestoreDB’s get() method returns a promise that resolves regardless of whether the target document exists or not. If the target document exists, the promise will resolve with an instance of a Firestore Document Snapshot containing all the data for our target document. If the document does not exist, the promise will still resolve to a Document Snapshot but the snapshot will contain no data. In this case, we direct fetchAnswer to throw an error. If the request to Firestore itself returns an error, FetchAnswer will similarly throw an error.

This is probably a good time to pause and check that fetchAnswer actually works, i.e. that it makes a valid request to Firestore. Let’s quickly connect our UI Button (in App.js) to fetchAnswer.

Drop the following code into App.js. I have bolded the sections where changes were made to the code.

import React, { Component } from 'react';

import { connect } from 'react-redux';

import fetchAnswer from './firestore/answers';

import { STATUS_ERROR } from './constants';

import logo from './logo.svg';

import './App.css'; /**

* renderError

*

* @param {String} msg Error message returned from Firestore

*/

function renderError(msg) {

return (

<div className="error">

<p className = "error-text">

{`Oh No! There was an error: ${msg}!`}

</p>

</div>

);

} class App extends Component {

/**

* Creates an instance of App

*/

constructor() {

super();

// The application currently only uses one question.

// If we were to add additional questions, we could store which was is active here.

this.activeQuestion = 'hello-firestore';

// We have added a state to store the response from Firestore

this.state = {

firestoreResponse: 'N/A'

};

this.makeFirestoreRequest = this.makeFirestoreRequest.bind(this);

} /**

* Kicks off request to Firestore

* @param {String} activeQuestion the documentID to query in Firestore

*/

makeFirestoreRequest(activeQuestion) {

fetchAnswer(activeQuestion).then((response) => {

this.setState({

firestoreResponse: response,

});

});

} render() {

const { firestoreResponse } = this.state;

const { activeQuestion } = this;

return (

<div className="App">

<header className="App-header">

<img src={logo} className="App-logo" alt="logo" />

<p className="firestore-question">

Hello Firestore!

</p>

<button

className="firestore-response-btn"

onClick={() => this.makeFirestoreRequest(activeQuestion)}

>

<p>

Get Firestore Answer

</p>

</button>

<p className="firestore-response-text">

{`Firestore says: '${firestoreResponse}'`}

</p>

</header>

</div>

);

}

}

* mapStateToProps/

* https://react-redux.js.org/using-react-redux/connect-mapstate

* As the first argument passed in to connect, mapStateToProps is used for

* selecting the part of the data from the store that the connected component needs.

* @param {any} state state found in redux store

*/

function mapStateToProps(state) {

return {

answerDetail: state.answerDetail,

};

} /*** mapStateToProps/* As the first argument passed in to connect, mapStateToProps is used for* selecting the part of the data from the store that the connected component needs.* @param {any} state state found in redux store*/function mapStateToProps(state) {return {answerDetail: state.answerDetail,}; export default connect(mapStateToProps)(App);

I won’t go into great detail into what the new code does as we will replace it when we connect our Redux store to FetchAnswer, but I do want to highlight a few important changes:

We have added a state and local variable called activeQuestion to our App class. The state stores the response from fetchAnswer. ActiveQuestion stores the id for the document we created in Step 2. We pass the state to the render() method in order to display Firestore’s response in the UI. We have removed references to our Redux state in render(). This is because our component no longer uses our Redux state. We will connect our component back to Redux later.

If you never terminated the local build in your CLI from Step 1, https://localhost:3000/ should have automatically updated with the changes we made to the codebase. Navigate to your browser. If you click the Get Firestore Answer button now, your browser should display the response you stored in your Firestore database from Step 2. Mine says ‘Hey! You’re awesome!!’

If you got this far, congrats! It doesn’t matter! We are about to mess it all up.

Step 5: Map Firestore’s response to Redux

Starting Point: https://github.com/borkjt9/firestore-react-redux/tree/firestore-redux

Wow, our application works! So we are done, right? Nope.

While the above code is indeed functional, it’s easy to see the issues our current design we will run into at scale. Right now we are using a single component and are making a single request to the database. That’s simple. But what if our application has multiple components? What if it has child components? What if each of these child components needs access to different data? What if they need to share data?

Enter Redux. The main benefit of Redux is that it makes maintaining application state simple. Redux stores an application’s state in a single location (i.e. the Redux store) and then feeds the state into each application’s components as needed. There is no more passing data up and down the component chain. Every component simply passes data to Redux, and Redux decides what to do next.

The building blocks of a Redux store are actions. Actions are payloads of information that are sent to your store’s reducer through Redux’s dispatch method. Each time an action is dispatched, the reducer updates the store’s state and passes the new state to dependent components accordingly.

Note that the only way to update a store’s state is through dispatching actions. So actions are super important.

Due to the asynchronous nature of Firestore requests, I like to organize my actions into three categories:

Starts: signifies that the request to Firestore is about to begin. Fulfills: signifies the response from Firestore has been received successfully. Errors: signifies the request to Firestore has returned an error.

For each type of action listed above, we are going to create an action and insert it into our FetchAnswer function. Each of these actions will return a type and payload. The type will later be used by our reducer to filter through the actions. The payload will contain the data the reducer will use to update the store’s state. In all instances, the payload will at the least contain the current status of the request (‘success’, ‘error’, or ‘pending’).

In our Actions folder, open fetch-answer.js. Replace the current code with the below.

// Use constants to reduce fat finger bugs. import {

FETCH_ANSWER_START,

FETCH_ANSWER_FULFILLED,

FETCH_ANSWER_ERRORED,

STATUS_PENDING,

STATUS_ERROR,

STATUS_SUCCESS

} from '../../constants'; // Start, Fulfilled, and Error Actions all report on the status of a request.

// They are called during the request to Firestore.

// They feed into the Answer Reducer. /**

* fetchAnswerStart

*

* @return {any} feeds into reducer

*/

export function fetchAnswerStart() {

return {

type: FETCH_ANSWER_START,

payload: { status: STATUS_PENDING },

};

} /**

* fetchAnswerFulfilled

* @param {String} response

* @return {any} feeds into reducer

*/

export function fetchAnswerFulfilled(response) {

return {

type: FETCH_ANSWER_FULFILLED,

payload: { status: STATUS_SUCCESS, response },

};

} /**

* fetchActiveSitesErrored

* @param {Error} error code & message

* @return {any} feeds into reducer

*/

export function fetchAnswerErrored(error) {

return {

type: FETCH_ANSWER_ERRORED,

payload: { status: STATUS_ERROR, error } ,

};

}

Key points on the above functions:

Fetch-answer.js has no default export. Each of these exports will be imported into modules as needed. The type keys in each of the function’s return objects are used by our Redux store to determine how to update its state. The succeeding logic is found in reducers/answer-reducer.js.

You will notice that the type keys reference variables from constants.js that we have not yet initialized. We need to add these variables or our application will throw undefined exceptions.

In constant.js, add variables for each of the imported constants above. It doesn’t really matter what we set the values of the variables to, because from here on out we will only reference the variable name and not the value it is assigned to, but for consistency I like to make my variable’s names for constants equal their values.

// You can literally assign constants here to any values.

// It doesn't matter as long as the references make sense. // Action Types. Feed into the reducer.

export const FETCH_ANSWER_START = 'FETCH_ANSWER_START';

export const FETCH_ANSWER_FULFILLED = 'FETCH_ANSWER_FULFILLED';

export const FETCH_ANSWER_ERRORED = 'FETCH_ANSWER_ERRORED'; // Statuses of requests to Firestore. Feed into the Reducer.

export const STATUS_PENDING = 'STATUS_PENDING';

export const STATUS_ERROR = 'STATUS_ERROR';

export const STATUS_SUCCESS = 'STATUS_SUCCESS'; // Collection ID in Firestore DB

export const COLLECTION_QUESTIONS = 'questions';

Now let’s insert our actions into our fetchAnswer function.

In the firestore folder, open answers.js. Import our newly created actions at the top of the file.

import FirestoreDB from './config';

import { COLLECTION_QUESTIONS } from '../constants'

import {

fetchAnswerStart,

fetchAnswerFulfilled,

fetchAnswerErrored,

} from '../redux/actions/fetch-answer';

We are now going to replace FetchAnswer’s return statements with dispatches to our Redux store. Because the state of our Redux store will automatically propagate through our application whenever an update occurs, there is no longer a need to return specific data via fetchAnswer.

Replace fetchAnswer with the new code below. I have bolded the changes from the previous version.

/**

* fetchAnswer - makes requests to Firestore

*

* @param {Function} dispatch Redux function dispatch

* @param {String} question the name of the document we are querying

* @return {any} feeds into reducer

*/ dispatch, question) {

dispatch(fetchAnswerStart());

// Calls to Firestore return a promise.

// If no document exists, the promise will still resolve.

FirestoreDB().collection(COLLECTION_QUESTIONS).doc(question).get()

.then((doc) => {

if (doc.exists) {

const { response } = doc.data();

dispatch(fetchAnswerFulfilled(response));

} else {

throw new Error('No Such Document');

}

})

.catch((error) => {

// List of Firestore errors:

dispatch(fetchAnswerErrored(error));

});

} export default function fetchAnswer(, question) {// Calls to Firestore return a promise.// If no document exists, the promise will still resolve.FirestoreDB().collection(COLLECTION_QUESTIONS).doc(question).get().then((doc) => {if (doc.exists) {const { response } = doc.data();} else {throw new Error('No Such Document');}).catch((error) => {// List of Firestore errors: https://firebase.google.com/docs/storage/web/handle-errors });

Key points on our new fetchAnswer function:

Dispatch, a built-in Redux method, is now passed in as a parameter. The places we have dispatched our actions should seem intuitive. We dispatch the Start action right before we make our request to Firestore. We dispatch the Fulfilled action if the document we are querying for exists. We dispatch the Errored action if the document does not exist or the request to Firestore returns an error. These actions will send the response from Firestore to our Redux store’s state via their payloads.

The last thing we need to do is update our store’s reducer to handle our newly minted actions. Drop the below code in answer-reducer.js.

// Use constants to reduce fat finger bugs.

import {

FETCH_ANSWER_START,

FETCH_ANSWER_FULFILLED,

FETCH_ANSWER_ERRORED,

} from '../../constants'; export default function (

state = {

response: 'N/A',

status: '',

error: {}

}, action

) {

switch (action.type) {

case FETCH_ANSWER_START:

case FETCH_ANSWER_FULFILLED:

case FETCH_ANSWER_ERRORED:

// es6 destructuring uses elipses to transform objects into key-value pairs

// any key-value pair in the action's payload will be assigned to the state

return { ...state, ...action.payload }

default:

return state;

}

}

Key points on the new reducer:

For each type of action, we assume that it contains a payload key that points to an object. The reducer uses the new destructuring syntax from ES6 to update the store’s state with all (key, value) pairs in the action’s payload.

Step 6: Display the response in the UI

Starting Point: https://github.com/borkjt9/firestore-react-redux/tree/step-six

Wow. You made it to the last step! We’re so close to having a real live app!

The last thing we need to do is pass our store’s state into the UI.

Navigate to app.js. Remember all that not-good code I told you not to worry about earlier? Great news! We are about to replace it with some really-good code!

First, let’s check that we have correctly imported what we need. The top of app.js should read as follows:

import React, { Component } from 'react';

import { connect } from 'react-redux';

import fetchAnswer from './firestore/answers';

import { STATUS_ERROR } from './constants';

import logo from './logo.svg';

import './App.css';

Next, modify makeFireRequest (which is connected to our UI Button’s onClick method) to no longer update the component’s state and call fetchAnswer. By passing dispatch as a parameter to fetchAnswer, it will have the ability to dispatch actions to our Redux store.

/**

* Kicks off request to Firestore

* @param {String} activeQuestion the documentID to query in Firestore

*/

makeFirestoreRequest(activeQuestion) {

const { dispatch } = this.props;

fetchAnswer(dispatch, activeQuestion));

}

Because our component no longer uses state, we can delete the state variable from the constructor(). This is one of the key benefits of Redux: it allows us to create stateless, and therefore simpler, components. Our new constructor() method should look like the below.

constructor() {

super();

// The application currently only uses one question.

// If we were to add additional questions, we could store which was is active here.

this.activeQuestion = 'hello-firestore';

// We have added a state to store the response from Firestore

this.makeFirestoreRequest = this.makeFirestoreRequest.bind(this);

}

Last, we need to update our UI to display the results from our Firestore requests, which are stored in our Redux store’s state.

To do so, we first must connect our Redux store to the component. This was already set up for us in Step 1 and no additional changes are needed, but it will be helpful to review.

To connect a React Component to Redux, we use Redux’s built-in method mapStateToProps and react-redux’s connect method. I have pasted the target code below for convenience.



* mapStateToProps

* https://react-redux.js.org/using-react-redux/connect-mapstate

* As the first argument passed in to connect, mapStateToProps is used for

* selecting the part of the data from the store that the connected component needs.

* @param {any} state state found in redux store

*/

function mapStateToProps(state) {

return {

answerDetail: state.answerDetail,

};

} /*** mapStateToProps* As the first argument passed in to connect, mapStateToProps is used for* selecting the part of the data from the store that the connected component needs.* @param {any} state state found in redux store*/function mapStateToProps(state) {return {answerDetail: state.answerDetail,}; export default connect(mapStateToProps)(App);

Now to we have access to our Redux store’s state, all that is left to do is update the UI. To do so, we have to update the component’s render() method with references to our store’s state.

Replace the render() method with the below. The changes from the previous version are in bold.

render() {

const { activeQuestion } = this;

const { answerDetail } = this.props;

const { response, status, error } = answerDetail

return (

<div className="App">

<header className="App-header">

<img src={logo} className="App-logo" alt="logo" />

<p className="firestore-question">

Hello Firestore! How are you?

</p>

<button

className="firestore-response-btn"

onClick={() => this.makeFirestoreRequest(activeQuestion)}

>

<p>

Get Firestore Answer

</p>

</button>

<p className="firestore-response-text">

{`Firestore says: '${response}'`}

</p>

{ status === STATUS_ERROR && renderError(error.message)}

</header>

</div>

);

}

Key points on the new render method:

We have deleted the reference to the component’s state (since it no longer exists), and have replaced it with a reference to the component’s props (which are really just pointers to our Redux store’s state). We have updated the Button in our UI to display the response from Firestore (which has been dispatched to our Redux store via a Fulfilled action). We display an error message if fetchAnswer has dispatched an Error action to our Redux store.

Navigate back to your browser. Fingers crossed it should have automatically reloaded with our new code without error. Click the Get Firestore Answer button on last time. If everything worked correctly, you should see the response we stored in Firestore in Step 2 prominently displayed in the browser.

That’s all folks.

Step 7: Give yourself a round of applause

Starting Point: https://github.com/borkjt9/firestore-react-redux/tree/completed-tutorial

Is the correct response displayed in your browser? Congrats! We’re finished!

I hope you enjoyed this tutorial and learned a little something about incorporating Firestore into React / Redux. I think all three technologies are absolutely wonderful and the more people I can help use them the better.

If any part of this tutorial was unclear or you need something to be explained in greater detail, feel free to shoot me a message!