DEV Community

aurel kurtula
aurel kurtula

Posted on • Updated on

Creating an app with react and firebase - part two

In this second part, we'll continue to develop the todo app but linking it to a firebase project.

I'm going to assume that you've read the previous tutorial and you have cloned the project from github and are ready to follow along.

The code we have so far is a functional application. You can run yarn start (or yarn install before that, if you haven't installed the packages) and see that we have a todo app where you can add items, mark them as complete, navigate between two routes and delete completed items.

Today we'll integrate our application with firebase. We'll end up using the database from firebase to manage the application state.

Then in the final part we'll deal with authentication.

Connecting to and using the database

Before we start coding we need to head over to firebase, create a project, and, just for now, change the database permission rules to true for both read and write.

I have already written an Introduction to firebase's real-time database which guides you through how to setup all that. I write this tutorial series believing that you know the basics of firebase database and authentication services, if you don't I recommend you read my corresponding tutorials first.

Configuring the database into react

First we need to install firebase:

yarn add firebase 
Enter fullscreen mode Exit fullscreen mode

Then we need to initialize firebase as we've done in the database introduction tutorial.

To keep the project uncluttered, let's create a ./src/fire.js file and add the following

import firebase from 'firebase';
const config = {
  apiKey: "**********",
    authDomain: "**********",
    databaseURL: "**********",
    projectId: "**********",
    storageBucket: "**********",
    messagingSenderId: "**********"
};
const fire = firebase.initializeApp(config)
export { fire }
Enter fullscreen mode Exit fullscreen mode

There's nothing new there, we import firebase, copy and paste the configuration code that firebase gave us - when we create the project at Introduction to firebase's real-time database. Then we export it. The reason we aren't using export default is because we'll export the different authentication methods from here later on.

Database CRUD

Head over at ./src/App.js and let's start interacting with the database. We'll modify the existing code so that instead of creating, reading, updating and deleting items in local state, we'll perform those operations in the database.

To quickly recap, at the moment we have a state with few hard coded items. What we really want is for the state to be populated from the database. So let's do that.

// no constructor 
state = {
  items: {}
}
itemsRef = fire.database().ref('items')
Enter fullscreen mode Exit fullscreen mode

We removed the hard-coded data from the state, then we instantiate an instance of the database reference (we basically tell firebase we need an items object for this project).

Finally, using one of the "lifecycle methods" of our App component (inherited by React.Component) called componentWillMount we can populate the state with the database data.

componentWillMount(){
  this.itemsRef.on('value', data=> {
    this.setState({
      items: data.val()
    })
  })
}
Enter fullscreen mode Exit fullscreen mode

From the documentation we learn that

componentWillMount() is invoked immediately before mounting occurs. It is called before render(), therefore calling setState() synchronously in this method will not trigger an extra rendering.

Hence it sounds as the correct "lifecycle method" for this purpose.

This article states that

[I]n ES6-style class components, the constructor plays the same role as componentWillMount, so if you already have a constructor, you can just put the code there.

Even though we do not have a constructor, it's still nice to know that we could have done something like this:

  constructor(props) {
    super(props);
    this.state = {
      items: {}
    }
    this.itemsRef = fire.database().ref('items')
    this.itemsRef.on('value', data=> {
      this.setState({
        items: data.val()
      })
    })
  }
Enter fullscreen mode Exit fullscreen mode

Finally, we should also remove the database binding when component unmounts. "Perform any necessary cleanup in this method, such as invalidating timers, canceling network requests"

  componentWillUnmount(){
    fire.removeBinding(this.itemsRef)
  }
Enter fullscreen mode Exit fullscreen mode

Creating items

In ./src/App.js we already have the functionality to add items in the local state. We no longer need to do that, we just interact with the database directly and let the "real-time" feature of firebase update the state.

  addItem=(e)=> {
    e.preventDefault();
    this.itemsRef.push({
      item: this.todoItem.value, 
      completed: false     
    })
  }
Enter fullscreen mode Exit fullscreen mode

Again, we've already covered this functionality. Remember, unlike when setting local state, firebase auto-generates the unique identifier for us. So over at firebase, the above code would generate something like this:

{
    "items": {
      "-L1Ds8FqPAPsFiXgUhQ2" : {
        "completed" : false,
        "item" : "Get Milk"
      }
    }
}
Enter fullscreen mode Exit fullscreen mode

Modifying items

Next, we already have the functionality to change completed from false to true.

  completeItem=(id)=>{  
    this.itemsRef.update({
      [id]:{
        ...this.state.items[id], 
        completed: true      
      }
    })
  }
Enter fullscreen mode Exit fullscreen mode

Similar to what we've already done, but this time around, we're updating the database content.

Deleting items

Using the same code as when we explored firebase databases let's delete a completed item.

deleteItem = (id) => {
this.itemsRef.update({
[id]: null
})
}
Enter fullscreen mode Exit fullscreen mode




Conclusion

That's it. The application is not ready for production, as we are basically allowing anyone to add data to our database. In the final part of this mini series we'll use authentication to restrict who can read and write the data.

The project as it stands so far can be found at the same github repository. As you'll see, I'm using different branches corresponding to each part of this series. Stay tuned for the third and final part

Top comments (0)