5 min read

Firebase is a realtime database for the modern web. Data in your Firebase is stored as JSON and synchronized in realtime to every connected client.

React is a JavaScript library for creating user interfaces. It is declarative, composable, and promotes functional code. React lets you represent your UI as a function of its state.

Together they are dynamite!

In this post we will explore creating a React application with a Firebase backend. We will take a look at how we can use Firebase as a Flux store to drive our UI.

Create a project

Our app will be an SPA (Single Page Application) and we will leverage modern JavaScript tooling. We will be using npm as a package manager, babel for ES2015+ transpilation, and browserify for bundling together our scripts.

Let’s get started.

$ mkdir todo && cd todo
$ npm init
$ npm install --save 
   [email protected] 
   [email protected] 
   firebase
$ npm install --save-dev 
   budo 
   babelify

We have now made a folder for our app todo. In that, we have created a new project using npm init (defaults are fine) and we have installed React, Firebase, and some other packages. I didn’t mention budo before, but it is a great browserify development server.

NOTE: At the time of writing, React is at version 0.13.3. In the next major release (0.14), React itself is decoupled from the DOM rendering. In order for this blogpost not to be obsolete in a matter of weeks we use the 0.14.0-rc1 version of React. Since we intend to render DOM nodes from our React components, we also need to install the react-dom module.

React basics

Let’s start by creating a basic React application. We will be making a list of TODO items.
Make a file index.js in the todo directory and open it in your favorite editor.

import React from 'react'
import ReactDOM from 'react-dom'

class TodoApp extends React.Component {
   constructor(props) {
       super(props)
       this.state = {
           todos : [
               { text : 'Brew coffee', id : 1 },
               { text : 'Drink coffee', id : 2 }
           ]
       }
   }
   render() {
       let todos = this.state.todos.map((todo) => <li key={todo.id}>{todo.text}</li>)
       return (
           <div className="todoAppWrapper">
               <ul>
                   {todos}
               </ul>
           </div>
       )
   }
}

ReactDOM.render(<TodoApp />, document.body)

Now we can run that application in a browser using budo (browserify under the hood).

$ budo index.js --live -- -t babelify

Navigate to http://localhost:9966/ and verify that you can see our two TODO items on the page.

Notice the –live parameter we pass to budo. It automatically enables livereload for the bundle. If you’re not familiar with it, get familiar with it!

Set up Firebase

For setting up a new Firebase, check out the below details on the subject.

FireFlux

To build large applications with React a good approach is to use the Flux application architecture. At the heart of Flux sits the store. A Flux store holds application state and trigger events whenever that state changes. Components listen to these events and re-render accordingly. This aligns perfectly with how Firebase works. Firebase holds your data/state and triggers events whenever something changes.

So what we are going to do is use our Firebase as a Flux store. We’ll call it FireFlux 🙂

Make a file fireflux.js in the todo directory and open it in your favorite editor.

import Firebase from 'firebase/lib/firebase-web'
import { EventEmitter } from 'events'

const ref = new Firebase('https://<name>.firebaseio.com/todos')
const fireflux = new EventEmitter()
fireflux.store = {
   todos : []
}
fireflux.actions = {
   addTodo : function(text) {
       ref.push({ text : text })
   },
   removeTodo : function(todo) {
       ref.child(todo.id).remove()
   }
}

ref.on('value', (snap) => {
   let val = snap.val() || []
   if (typeof val == 'object') val = Object.keys(val).map((id) => {
       let todo = val[id]
       todo.id = id
       return todo
   })
   fireflux.store.todos = val
   fireflux.emit('change')
})


export { fireflux as default }

Notice we import the firebase/lib/firebase-web library from the Firebase module. This module includes both a browser and node version of the Firebase library; we want the browser version.

The fireflux object is an EventEmitter. This means it has functionality like .on() to listen and .emit() to trigger events. We attach some additional objects: store and actions. The store will hold our todo, and the actions are just convenience functions to interact with our store.

Whenever Firebase has updated data – ref.on(‘value’, fn) – it will update fireflux.store.todos and trigger the change event.

Let’s see how we can hook this up to our React components.

import React from 'react'
import ReactDOM from 'react-dom'
import fireflux from './fireflux'

class TodoApp extends React.Component {
   constructor(props) {
       super(props)
       this.state = {
           todos : []
       }
   }
   render() {
       let todos = this.state.todos.map((todo) => {
           return (
               <li key={todo.id}>
                   <button onClick={this.removeTodo.bind(this, todo)}>done</button>
                   {todo.text}
               </li>
           )
       })
      return (
           <div className="todoAppWrapper">
               <button onClick={this.addTodo}>Add</button>
               <ul>
                   {todos}
               </ul>
           </div>
       )
   }
   addTodo() {
       let todo = window.prompt("Input your task")
       fireflux.actions.addTodo(todo)
   }
   removeTodo(todo) {
       fireflux.actions.removeTodo(todo)
   }
   componentDidMount() {
       fireflux.on('change', () => {
           this.setState({ todos : fireflux.store.todos })
       })
   }
}

ReactDOM.render(<TodoApp />, document.body)

First, take a look at TodoApp’s componentDidMount. It sets up a listener for FireFlux’s change event and updates its state accordingly. Calling this.setState on a React component triggers a re-render of the component.

We have also included an Add and some done buttons. They make use of fireflux.actions.* to interact with Firebase. Give them a try and notice how the interface automatically updates when you add and finish items.

Hopefully you can now hit done for the last one!

About the author

Asbjørn Enge is a software enthusiast living in Sandes, Norway. He is passionate about free software and the web. He cares about modular design, simplicity, and readability and his preferred languages are Python and JavaScript. He can be found on Twitter @asbjornenge

LEAVE A REPLY

Please enter your comment!
Please enter your name here