React with Firebase: Firestore setup
Tags: react, serverless
Published: 2020-01-13 00:30:03

__who is this article for?__

anyone trying to set up a serverless database option. 

To be sure I don't waste your time and this is actually what you are looking for... 

this is the [github repo](https://github.com/TallanGroberg/firestore-tutorial)

this is the working product on [surge](https://firestore-tutorial.surge.sh/)

__how to use it?__

think of this as a small piece of functionality to incorporate into a much larger app.

__what we will learn.__

this is an example of the most basic firestore setup for a react application. 

__prerequisites__:

create-react-app installed.

[firebase account](https://firebase.google.com/)

understanding of react and javascript. 

basic understanding of npm and firebase.

I will be using bash command line as well as vscode  

the first thing we need to do is set up our firebase app inside the firebase console. 

if you don't have a firebase console already you can make one by clicking [here to get started](https://firebase.google.com/)

click add project. 


![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/u7abpzlp11nfv05dy3nd.png)

name your project.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/bbhsct5jakt3aq0w0zfb.png)


select your default account.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/v3rmvhwehoial7dnu7l9.png)

click where it says database. 

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/1q5ny6huzg2g9nc42stj.png)


click where it says to make a database.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/6uo855u0z3cb8zxjhrvh.png)

start in test mode and once everything is working change back to production mode. 

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/t0brm4n2z8pojwny7bpf.png)

choose a location. Ideally where your users are likely to be and not necessarily where you are.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/kehkazn4rpjj3a6wnczf.png)

next you need to register your app. 

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/58b0cyoxyahliust8ihp.png)

name your app. 

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/an6a91deqr633syg731d.png)

now we need to add firebase to our react app. 

start by making a new react app from the command-line.

```bash 
create-react-app firestore-tutorial
```

cd into the app 

```bash
cd firestore-tutorial
```

once installed, make a new folder called firebase __inside__ the src folder. you can make the file at the same time too!

```bash
mkdir src/firebase && touch src/firebase/index.js
```

The above command will make a folder by walking down the folder structure and then, after the && sign, it will make a file in the folder you just created.

start your server by going back to the command line to running npm start

```bash
npm start
```

now we go back to the firebase console and grab our firebase SDK and set that up inside of a file that we can use app wide. 

hover on the cog __next to__ project overview in the top left corner of the project page and click on project settings.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/0zpdr5nycavo302mo59k.png)


this takes you to a page providing __general__ settings. scroll down to the __your apps__ section and you will see an HTML snippet. 

if this was _just_ javascript then we _would_ need to add this to the index.html of the webpage. 

since this is a React project we have to add only the javascript inside the script tag and add that to the index.js __inside the firebase folder__

copy and paste your firebase SDK into your firebase/index.js (remember that this is different from you index.js below your App.test.js inside the src folder.)

add the exports and imports, it should look something like this. 

```javascript

import firebase from 'firebase'
import 'firebase/firestore'

firebase.initializeApp({
  apiKey: "super secret don't tell",
  authDomain: "firestore-tutoral-the-first.firebaseapp.com",
  databaseURL: "https://firestore-tutoral-the-first.firebaseio.com",
  projectId: "firestore-tutoral-the-first",
  storageBucket: "firestore-tutoral-the-first.appspot.com",
  messagingSenderId: "super secret don't tell",
  appId: "super secret don't tell",
  measurementId: "super secret don't tell"
});


let db = firebase.firestore()


export default {
  firebase, db
}
```

now import firebase into the App.js at the top of the file like so.

```javascript
import firebase from './firebase/index'
```

then inside the App component add a console log

```javascript
console.log(firebase)
```

open the dev tools and you should see your config object. 

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/lwz9yk9cxafs7b3dybf5.png)

now you have access to firebase at the top of your component tree which means that you have firebase anywhere in your app. 



now make sure that you have access to your database by adding __.db__ to the console.log

```javascript
console.log(firebase.db)
```

in the dev tools, you should see Firestore with all its helper methods. 

let's use the infamous _todo list_ to test our firestore capabilities.

I always like to break down my development into the smallest possible step forward. this means sending anything at all the firestore. 

set up the function for firestore like so. 

```javascript 
firebase.db.collection('todo').add({})
```

we want to know what happened after we sent it, we want this function to let us know if it sent or failed. A prefect case for __.then__ and __.catch__ 

change the function to look like this. 

```javascript

 firebase.db.collection('todo').add({title: 'first todo', description: 'new todo' })
    .then(documentReference => {
      console.log('document reference ID', documentReference.id)
    })
    .catch(error => {
      console.log(error.message)
    })

```

this is almost exactly [like the docs](https://firebase.google.com/docs/firestore/quickstart?authuser=0)

now we want to add the button to send this to firebase. To do that, we need to make this function a variable so that we don't have to add this whole function inside an onClick for a button.


after you get rid of all the react boiler plate and add the sendTodo in front of the firebase.db function you should have a component that looks like this.

```javascript
import React from 'react';
import firebase from './firebase/index'

const App = () => {

  console.log(firebase.db)

  const sendTodo = () => { firebase.db.collection('todo').add({title: 'first todo', description: 'new todo' })
    .then(documentReference => {
      console.log('document reference ID', documentReference.id)
    })
    .catch(error => {
      console.log(error.message)
    })

  }

  return (
    <div>
      <h1>send todo</h1>
        <button onClick={sendTodo}>click here to send</button>
    </div>
  );
};

export default App;

```

go to localhost:3000 and click the button to send todo. 


this will give you a document reference id. 


![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/7pzmu4bpba5lkcn6xrjo.png)

if you go back to your firebase console and click on database. 

You will notice that some changes have occurred. 

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/ys3lanod96t749z7j0pm.png)

__congrats!!__

you have set up a serverless react app. 


we still have to get this displayed to the screen.

the best practice would be to save everything to state as soon as the component renders. 

a perfect job for useState to store the todos and useEffect to save them as soon as the component renders. 

add useState and useEffect at the top.

```javascript
import React, {useEffect, useState} from 'react';
```

make the piece of state at the top of the component. 

```javascript
  const [todos, setTodos] = useState([])

```

the todo is an object, so we want todos to be an array of objects [{..}, {..} ect...]

now make the function to get the data from firestore and save it to the todos state with useEffect.

```javascript
useEffect( () => {
        getTodos()
    }, [])

    const getTodos = () => {
      firebase.db.collection('todo').get()
        .then(querySnapshot => {
        querySnapshot.forEach( doc => {

          setTodos(prev => ([...prev, doc.data()]))
        })
      })
      .catch(err => {
        console.log(err.message)
      })
    }

```

now we can display those todos to the browser.

add this line inside the render method and div 

```javascript
        {todos.length === 0 ? null : todos.map(todo => <h1 >{todo.title}</h1>) }
```

here is what the App.js looks like so far...

```javascript
import React, {useEffect, useState} from 'react';
import firebase from './firebase/index'

const App = () => {
  const [todos, setTodos] = useState([])

    useEffect( () => {
        getTodos()
    }, [])

    const getTodos = () => {
      firebase.db.collection('todo').get()
        .then(querySnapshot => {
        querySnapshot.forEach( doc => {
          setTodos(prev => ([...prev, doc.data()]))
        })
      })
      .catch(err => {
        console.log(err.message)
      })
    }


  const sendTodo = () => {
    firebase.db.collection('todo').add({title: 'first todo', description: 'new todo', })
    .then(documentReference => {
      console.log('document reference ID', documentReference.id )
    })
    .catch(error => {
      console.log(error.message)
    })
  }

   
  return (
    <div>
      <h1>send todo</h1>
        <button onClick={sendTodo}>click here to send</button>
         {todos.length === 0 ? null : todos.map(todo => <h1 >{todo.title}</h1>) }
    </div>
  );
};
export default App;

```

now let's make it so that we send data based on user input. 

let's make an initial state and have form inputs equal that, it will be an object.

```javascript
const initstate = { title: '', description: ''}
  const [inputs, setInputs] = useState(initstate)
```

add the form and input fields to change this state.

```javascript
 <form onSubmit={sendTodo}>
          <input name='title'
            placeholder="title" 
            value={inputs.title}
            onChange={handleChange}/>
          <input 
            name='description'
            value={inputs.description} 
            placeholder="description" 
            onChange={handleChange}/>
            <button>send todo</button>
        </form>

```

make the handleChange function 

```javascript
const handleChange = e => {
    const {name, value} = e.target
    setInputs(prev => ({...prev, [name]: value}))
  }
```

lets add a the event object _e for short_ to the sendTodo and  e.preventDefault() to keep it form automatically refreshing. 

the first __2__ lines of the sendTodo() function should look like this. 

```javascript
 const sendTodo = (e) => {
    e.preventDefault()

```



the new getTodos() will look like this now.


```javascript
const getTodos = () => {
      firebase.db.collection('todo').get()
        .then(querySnapshot => {
        querySnapshot.forEach( doc => {
          setTodos(prev => ([...prev, doc.data()]))
        })
      })
      .catch(err => {
        console.log(err.message)
      })
    }

```

this isn't best practice but it will work for learning purposes. 

now call on the getTodos() in the sendTodos() under the  console.log('document reference ID', documentReference.id)

the new sendTodo() will look like this. 

```javascript
const sendTodo = (e) => {
    e.preventDefault()
    firebase.db.collection('todo').add(inputs)
    .then( async documentReference => {
      console.log('document reference ID', documentReference.id)
      await setTodos([])
      getTodos()
    })
    .catch(error => {
      console.log(error.message)
    })
  }

```

we make some async and await magic happen in the __.then__ this is because it will duplicate state (__Not firestore__) everytime you add a todo. we are making this function await us setting state back to empty and only after are we repopulating state.  

finding a better way to do this is an exercise I will leave to you. after you figure it out leave the technique you used in the comments.  

and the whole App.js with everything working will look like this.

```javascript
import React, {useEffect, useState} from 'react';
import firebase from './firebase/index'



const App = () => {
  const [todos, setTodos] = useState([])
  const initstate = { title: '', description: ''}
  const [inputs, setInputs] = useState(initstate)

    useEffect( () => {
        getTodos()
   
        
    }, [])
    const getTodos = () => {
      firebase.db.collection('todo').get()
        .then(querySnapshot => {
        querySnapshot.forEach( doc => {
          
          setTodos(prev => ([...prev, doc.data()]))
        })
      })
      .catch(err => {
        console.log(err.message)
      })
    }
    
    
    const sendTodo = async (e) => {
      e.preventDefault()
      await firebase.db.collection('todo').add(inputs)
      .then( async documentReference => {
        console.log('document reference ID', documentReference.id)
        await setTodos([])
     // set todos back to an empty array before re-fetching the whole db.
        getTodos()
      })
      .catch(error => {
        console.log(error.message)
      })
     
  }

  const handleChange = e => {
    const {name, value} = e.target
    setInputs(prev => ({...prev, [name]: value}))
  }

   
  return (
    <div>
      <h1>send todo</h1>
        <form onSubmit={sendTodo}>
          <input name='title'
            placeholder="title" 
            value={inputs.title}
            onChange={handleChange}/>
          <input 
            name='description'
            value={inputs.description} 
            placeholder="description" 
            onChange={handleChange}/>
            <button>send todo</button>
        </form>


         {todos.length === 0 ? <p>make  your first todo</p> : todos.map(todo => <h1 >{todo.title}</h1>) }
    </div>
  );
};

export default App;


```

that's it, you now have a static website with the use of a server. 

obviously there is a lot to do to make this a functional website but this was about getting started with firestore, if you want to make another CRUD app there are a lot of tutorials on how to do so. The only way you can become a better developer is by memorizing the small lego pieces and practicing how to put them together.

_conclusion..._ 

every problem you run into is an opportunity to strengthen your technical sophistication as a developer. that being said. see if you can figure out how to make this a full CRUD app without finding another tutorial.

the [docs](https://firebase.google.com/docs/firestore/quickstart?authuser=0) are a great resource


__if you liked this article please share and subscribe. if you didn't like it please tell me why and I will improve everytime I get feedback__ 

the [github for this article.](https://github.com/TallanGroberg/firestore-tutorial) 

see the working project. 


_thanks_