Firebase as simple database to React app
Nathan Sebhastian

Nathan Sebhastian @codewithnathan

About: JavaScript Full Stack Developer currently working with fullstack JS using React and Express. Follow me if you’re interested in web development stuff

Joined:
Jul 12, 2018

Firebase as simple database to React app

Publish Date: Feb 13 '19
157 15

Firebase is an all-in-one backend as a service provider (BaaS) that provides database, authentication, cloud storage among their many services. In this tutorial you're going to learn how to use Firebase Real Time Database service in React application.

You're going to build a simple team list application, where users can add, delete and edit team member information.

Create your database application

First, you need to create your application in Firebase console.

Then head over to the Database menu and scroll a bit down into Choose Real Time Database section.

Creating real time database

Set the security rules to start in test mode.

(this makes your database insecure, but it's okay for the purpose of this tutorial.)

Finally, get the configuration needed to integrate Firebase into your web app.

Creating real time database

Grab the source code from this codesandbox and fork it:

And put your credential in the config file:

const config = {
  apiKey: "{YOUR KEY}",
  authDomain: "{YOUR KEY}",
  databaseURL: "{YOUR KEY}",
}

export default config;
Enter fullscreen mode Exit fullscreen mode

Setting up your React application

Start your React application with create-react-app

npx create-react-app react-firebase-basic
Enter fullscreen mode Exit fullscreen mode

Then install firebase and Bootstrap (so you can skip writing your own css.)

npm i firebase bootstrap
Enter fullscreen mode Exit fullscreen mode

Then you can remove everything from src/ since you don't need most of the boilerplates

Creating config.js file

Let's write Firebase configuration in a separate config.js file:

const config = {
  apiKey: "{YOUR KEY}",
  authDomain: "{YOUR KEY}",
  databaseURL: "{YOUR KEY}",
}

export default config;
Enter fullscreen mode Exit fullscreen mode

You'll import this config into your App.js later.

Write the index.js file

This file will serve as React entry point:

import React from 'react';
import ReactDOM from 'react-dom';
import 'bootstrap/dist/css/bootstrap.css';
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));
Enter fullscreen mode Exit fullscreen mode

Creating your application

It's time to write your App.js file. Let's initialize our Firebase App in the constructor:

import React from 'react';

import Firebase from 'firebase';
import config from './config';


class App extends React.Component {

  constructor(props){
    super(props);
    Firebase.initializeApp(config.firebase);

    this.state = {
      developers: []
    }
  }

  //...
Enter fullscreen mode Exit fullscreen mode

Then you can write the logic for getting and saving data: writeUserdata will write our state into the database, while getUserData will create a listener on / path, and on value changes, we will assign snapshot value as state.

writeUserData = () => {
  Firebase.database().ref('/').set(this.state);
  console.log('DATA SAVED');
}

getUserData = () => {
  let ref = Firebase.database().ref('/');
  ref.on('value', snapshot => {
    const state = snapshot.val();
    this.setState(state);
  });
  console.log('DATA RETRIEVED');
}
Enter fullscreen mode Exit fullscreen mode

Put these writeUserData and getUserData in componentDidMount and componentDidUpdate respectively.

componentDidMount() {
  this.getUserData();
}

componentDidUpdate(prevProps, prevState) {
  // check on previous state
  // only write when it's different with the new state
  if (prevState !== this.state) {
    this.writeUserData();
  }
}
Enter fullscreen mode Exit fullscreen mode

All that's left is to write the render and handle submit form logic: We will map our developers array from state and put each item in a card component. Each card will have a delete and update button. On delete clicked, we will filter out the specific item, while on update clicked, we will get the item data into the form.

handleSubmit will insert data when uid value is false and update data when it is true. We're using refs to get data from form inputs.

// ...
render() {
  const { developers } = this.state;
  return(
    <div className="container">
      <div className="row">
        <div className='col-xl-12'>
          <h1>Firebase Development Team</h1>
        </div>
      </div>
      <div className='row'>
        <div className='col-xl-12'>
        { 
          developers
          .map(developer => 
            <div key={developer.uid} className="card float-left" style={{width: '18rem', marginRight: '1rem'}}>
              <div className="card-body">
                <h5 className="card-title">{ developer.name }</h5>
                <p className="card-text">{ developer.role }</p>
                <button onClick={ () => this.removeData(developer) } className="btn btn-link">Delete</button>
                <button onClick={ () => this.updateData(developer) } className="btn btn-link">Edit</button>
              </div>
            </div>
            )
        } 
        </div>
      </div>
      <div className='row'>
        <div className='col-xl-12'>
          <h1>Add new team member here</h1>
          <form onSubmit={ this.handleSubmit }>
            <div className="form-row">
              <input type='hidden' ref='uid' />
              <div className="form-group col-md-6">
                <label>Name</label>
                <input type="text" ref='name' className="form-control" placeholder="Name" />
              </div>
              <div className="form-group col-md-6">
                <label>Role</label>
                <input type="text" ref='role' className="form-control" placeholder="Role" />
              </div>
            </div>
            <button type="submit" className="btn btn-primary">Save</button>
          </form>
        </div>
      </div>
    </div>
  )
}

handleSubmit = (event) => {
  event.preventDefault();
  let name = this.refs.name.value;
  let role = this.refs.role.value;
  let uid = this.refs.uid.value;

  if (uid && name && role){
    const { developers } = this.state;
    const devIndex = developers.findIndex(data => {
      return data.uid === uid 
    });
    developers[devIndex].name = name;
    developers[devIndex].role = role;
    this.setState({ developers });
  }
  else if (name && role ) {
    const uid = new Date().getTime().toString();
    const { developers } = this.state;
    developers.push({ uid, name, role })
    this.setState({ developers });
  }

  this.refs.name.value = '';
  this.refs.role.value = '';
  this.refs.uid.value = '';
}

removeData = (developer) => {
  const { developers } = this.state;
  const newState = developers.filter(data => {
    return data.uid !== developer.uid;
  });
  this.setState({ developers: newState });
}

updateData = (developer) => {
  this.refs.uid.value = developer.uid;
  this.refs.name.value = developer.name;
  this.refs.role.value = developer.role;
}
Enter fullscreen mode Exit fullscreen mode

Now your React application is ready to read and set data into your Firebase database. Here is the final demo again:

You might wonder is it safe to put Firebase Api key in the config where experienced programmers can easily get it. Actually, it’s okay to put it there because Firebase has security rules that ensures only authenticated users can access your database. I just haven’t setup the security rules in this tutorial.

I will write a more complete tutorial that covers authentication, database rules and using Firebase cloud storage for user uploaded images in my next post, so stay tuned!

Comments 15 total

  • Andy Preston
    Andy PrestonFeb 13, 2019

    Excuse me if I've missed something. But surely having your API key inside the create-react-app will expose your backend to abuse.

    Someone with knowledge of JavaScript could easily find the API key within your code and use the key to write whatever they want to the database?

    • Nathan Sebhastian
      Nathan SebhastianFeb 13, 2019

      Oh none at all, you're right on point. I've also wondered the same thing until I came to this post:

      javebratt.com/hide-firebase-api/

      I won't put anything into my Firebase project except for this tutorial, so for all purpose I think it will be fine.

    • Jeff
      JeffNov 26, 2019

      It is safe to include the config in your app. The Firebase docs address this:

      A Firebase config file or config object associates your app with your Firebase project and its resources (databases, storage buckets, etc.).

      The content is considered public, including your platform-specific ID (entered in the Firebase console setup workflow) and values that are specific to your Firebase project, like your API Key, Realtime Database URL, and Storage bucket name. Given this, use security rules to protect your data and files in Realtime Database, Cloud Firestore, and Cloud Storage.

  • Sandor Dargo
    Sandor DargoFeb 14, 2019

    Thanks for the article!

    Is this going to be a series? Are you planning to write about Firebase as an authenticator?

    • Nathan Sebhastian
      Nathan SebhastianFeb 14, 2019

      Thank you Sandor! I actually haven't taught about that.. you just give me a new idea! I will try to come up with a more advanced Firebase integration. Stay tuned!

  • Edison Augusthy
    Edison AugusthyFeb 14, 2019

    waiting for new posts

  • Michael Caveney
    Michael CaveneyFeb 15, 2019

    Very handy, thanks for taking the time to write this up!

  • ann lin
    ann linFeb 15, 2019

    NOICE

  • Mika Kaakinen
    Mika KaakinenMar 17, 2019

    A good tutorial.

  • Hemant Patil
    Hemant PatilApr 24, 2019

    i am getting error while putting the mine keys of firebase project, so how to solve it?

    • Nathan Sebhastian
      Nathan SebhastianApr 28, 2019

      What error did you see in the console? It might be something with the security rule

  • EchoEye
    EchoEyeJul 10, 2019

    Good tutorial and very useful. It works well in develop mode but during production build, it says something like:

    "Reference error: IDBIndex is not defined" and cancels the build

  • Robert
    RobertMar 10, 2020

    I ran into an issue with Firebase to where whenever my e.preventDefault() is right after my onSubmit handler, it will not add data to my db in prod. It works fine in development which is odd. Check out what I wrote:

    onSubmit = e => {
    e.preventDefault();
    const { fullName, email, subject, message, error } = this.state;
    let contactID = email;
    db.collection("formContacts")
    .doc(contactID)
    .set({
    fullName: fullName,
    email: email,
    subject: subject,
    message: message
    })
    .then(
    (window.location = "/formSuccess").this
    .setstate({ ...INITIAL_STATE })
    .catch(
    (window.location = "/formError").this.setstate({ ...INITIAL_STATE })
    )
    );
    };

    Any thoughts?

    • Nathan Sebhastian
      Nathan SebhastianMar 15, 2020

      Hello Robert, sorry for late reply. I don't know what's wrong by simply looking at your code. There may be several causes for it. I recommend you try these suggestions:
      Does the catch call ever run when you do it?
      Or maybe you had the wrong credentials for production environment?

      If you don't have any React error in the console, most likely something is wrong in the process of saving your data to Firebase.

      Hope this helps!

  • Ethan Klein
    Ethan KleinMar 30, 2020

    Thanks for the clear tutorial Nathan.
    Is it possible to connect a front-end-only react app to firebase WITHOUT using "test" mode. I've been struggling to successfully connect my react apps to firestore other than through "test" mode. Any help would be greatly appreciated. Also, i'm fairly certain other people have similar concerns as there isn't much on stack overflow, reddit, etc. to answer this question

Add comment