Why Firebase?

Using Firebase will make it very easy for us to show real-time data to the user. Once a user votes on a link, the feedback will be instantaneous. Firebase’s Realtime Database will help us in developing this feature. Also, it will help us to understand how to bootstrap a React application with Firebase.

Why React?

React is particularly known for creating user interfaces using a component architecture. Each component can contain internal state or be passed data as props. State and props are the two most important concepts in React. These two things help us determine the state of our application at any point in time. If you’re not familiar with these terms, please head over to the React docs first.

Note: you can also use a state container like Redux or MobX, but for the sake of simplicity, we won’t be using one for this tutorial.

Structuring the app

For maintenance, I always like to separate my containers and components. Containers are the smart components that contain the business logic of our application and manage Ajax requests. Components are simply dumb presentational components. They can have their own internal state, which can be used to control the logic of that component (e.g. showing the current state of a controlled input component).

After removing the unnecessary logo and CSS files, this is how your app should look now. We created a components folder and a containers folder. Let’s move App.js inside the containers/App folder and create registerServiceWorker.js inside the utils folder.

The Router component wraps all the Route components. Based on the path prop of the Route component, the component passed to the component prop will be rendered on the page. Here, we’re setting up the root URL (/) to load our App component using the Router component.

Adding Firebase

If you don’t have a Firebase account, create one now (it’s free!) by going to their website. After you’re done creating a new account, log in to your account and go to the console page and click on Add project.

Enter the name of your project (I’ll call mine reddit-clone), choose your country, and click on the Create project button.

Now, before we proceed, we need to change the rules for the database since, by default, Firebase expects the user to be authenticated to be able to read and write data. If you select your project and click on the Database tab on the left, you’ll be able to see your database. You need to click on the Rules tab on the top that will redirect us to a screen which will have the following data:

{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}

We need to change this to the following:

{
"rules": {
".read": "auth === null",
".write": "auth === null"
}
}

This will let users update the database without logging in. If we implemented a flow in which we had authentication before making updates to the database, we would need the default rules provided by Firebase. To keep this application simple, we won’t be doing authentication.

Important: if you don’t make this modification, Firebase won’t let you update the database from your app.

Now, let’s add the firebase npm module to our app by running the following code:

npm install --save firebase

Next, import that module in your App/index.js file as:

// App/index.js
import * as firebase from "firebase";

When we select our project after logging in to Firebase, we’ll get an option Add Firebase to your web app.

If we click on that option, a modal will appear that will show us the config variable which we will use in our componentWillMount method.

Let’s create the Firebase config file. We’ll call this file firebase-config.js, and it will contain all the configs necessary to connect our app with Firebase:

In the componentWillMount() lifecycle hook, we use the package firebase we just installed and call its initializeApp method and passed the config variable to it. This object contains all the data about our app. The initializeApp method will connect our application to our Firebase database so that we can read and write data.

Let’s add some data to Firebase to check if our configuration is correct. Go to the Database tab and add the following structure to your database:

Clicking on Add will save the data to our database.

Now, let’s add some code to our componentWillMount method to make the data appear on our screen:

firebase.database() gives us a reference to the database service. Using ref(), we can get a specific reference from the database. For example, if we call ref('posts'), we’ll be getting the posts reference from our database and storing that reference in postsRef.

postsRef.on('value', …) gives us the updated value whenever there’s any change in the database. This is very useful when we need a real-time update to our user interface based on any database events.

Using postsRef.once('value', …) will only give us the data once. This is useful for data that only needs to be loaded once and isn’t expected to change frequently or require active listening.

After we get the updated value in our on() callback, we store the values in our posts state.

Now we’ll see the data appearing on our console.

Also, we’ll be passing this data down to our children. So, we need to modify the render function of our App/index.js file:

The main objective here is to make the posts data available in all our children components, which will be passed through react-router.

We’re checking if this.props.children exists or not, and if it exists we clone that element and pass all our props to all our children. This is a very efficient way of passing props to dynamic children.

Calling cloneElement will shallowly merge the already existing props in this.props.children and the props we passed here (firebaseRef, posts and loading).

Using this technique, the firebaseRef, posts and loading props will be available to all routes.

Here, the handleChange method updates our state with the value present in the input box. Now, when we click on the button, the handleSubmit method is triggered. The handleSubmit method is responsible for making the API request to write to our database. We do it using the firebaseRef prop that we passed to all the children.

this.props.firebaseRef.push({
title: this.state.title
});

The above block of code sets the current value of the title to our database.

After the new post has been stored in the database, we make the input box empty again, ready to add a new post.

We changed the firebase prop from firebaseRef: firebase.database().ref('posts') to firebase: firebase.database() because we’ll be using Firebase’s set method to update our voting count. In this way, if we had more Firebase refs, it would be very easy for us to handle them by using only the firebase prop.

Before proceeding with the voting, let’s modify the handleSubmit method in our src/containers/AddPost/index.js file a little bit:

In these two methods, whenever a user clicks on either of the buttons, the respective count is incremented in the database and is instantly updated in the browser.

If we open two tabs with localhost:3000/posts and click on the voting buttons of the posts, we’ll see each of the tabs get updated almost instantly. This is the magic of using a real-time database like Firebase.

In the repository, I’ve added the /posts route to the IndexRoute of the application just to show the posts on localhost:3000 by default. You can check that commit on GitHub.

Conclusion

The end result is admittedly a bit barebones, as we didn’t try to implement any design (although the demo has some basic styles added). We also didn’t add any authentication, in order to reduce the complexity and the length of the tutorial, but obviously any real-world application would require it.

Firebase is really useful for places where you don’t want to create and maintain a separate back-end application, or where you want real-time data without investing too much time developing your APIs. It plays really well with React, as you can hopefully see from the article.

I hope this tutorial helps you in your future projects. Please feel free to share your feedback in the comments section below.