Creating my first React app with Firebase🔥 integration, AntDesign and Reach Router
Tags: firebase, react, antdesign, reachrouter
Published: 2019-11-03 23:20:17

---
title: Creating my first React app with Firebase🔥 integration, AntDesign and Reach Router
published: true
description: 
tags: firebase, react, antdesign, reach-router
---

I recently started to get on the React train and what better way to jump in than following some courses and building an app. Since everything is moving into cloud these days, I also wanted to try this thing called Firebase🔥. I heard a lot about it and it seemed like a good time to use it.

In order to keep this article relatively short, I will explain the base setup and how everything ties together. I will create a trimmed version of the app to explain the basics. You can find the full project on my [Github](https://github.com/Nyalothas/MeetingsList).

## Getting Started

Being an Angular developer the first thing I looked for was an alternative to the angular cli environment so that I get some fast boilerplate setup.

I quickly found [Create React App](https://create-react-app.dev/docs/getting-started/). The only prerequisite that I needed was to make sure that I had `npm 5.2+` and `Node 8.10+` installed. You can check the versions using `npm -v` and `node -v` commands.

Then run the next command at your desired location and replace **my-app** with your app name. I will call it meeting-list.

```
npx create-react-app my-app
```

⚠ **Note:** If your username contains spaces npx will fail to create a directory -> [Github issue link](https://github.com/facebook/create-react-app/issues/6512). In this case you will need to install create-react-app globally then run the command.🙄

```
npm install -g create-react-app
```

```
create-react-app my-app
```

Now that we got that out of the way, we can test the app to make sure it's working. Change the directory to point to your app using `cd my-app` then run the command `npm run start`. If everything went well a browser tab will open at the location(if something else is not running on that port) `http://localhost:3000/` and we can see our app. Yaay!

## SSStyle with [AntDesign](https://ant.design/)

Cool cool, we got an app working, but it lacks style. Let's add some.

Stop the development server, if it's running(`Ctrl+C`). Run the next command to install antd React UI library.

```
npm install antd --save
```

Now that the library is installed we need to import the base css files. Let's open the `index.js` file from under the `src` folder.

Paste the following line before the import of `'./index.css'`.

```
import "antd/dist/antd.css";
```

Aand we finished the setup of Antd. Eazy! 👌

## 🔥 Firebase integration

Before we start to create some base components and interractions we need to set up Firebase.

The first step is to add the firebase package to our project.

```
npm install firebase --save
```

Next we need a Firebase account. Since Firebase is owned by Google we can create one fast using a Google email.

 - Navigate to [Firebase](https://firebase.google.com/) and create an account
 - Go to [Firebase Console](https://console.firebase.google.com/)
 - Select *Add project*
 - Enter a project name
 - (Optional) - Enable analytics

 After the project is created, click on it(this will open the project console).

 - Click on *Add app* , select the *Web* icon and enter a name for your app then *Register app*
 - Copy the content of the `firebaseConfig` object

 Let's create a new directory under `src` and call it `components`. Here I'm going to create a new file and name it `Firebase.js`. This is where we will keep our firebase config.

 Open `Firebase.js` and add the following lines of code. Paste inside of `firebaseConfig` the config object received from the firebase console for your project.

 ```js
import firebase from 'firebase/app';
import 'firebase/database';
import 'firebase/auth';

// Your web app's Firebase configuration
const firebaseConfig = {
    
};

// Initialize Firebase
firebase.initializeApp(firebaseConfig);

export const provider = new firebase.auth.GoogleAuthProvider();
export const auth = firebase.auth();

export default firebase;
 ```

 ⚠ Note: If you decide to publish this to Github or something similar make sure to delete the content of the  `firebaseConfig` object.

 **Enable Firebase Authentication**

 - In the Firebase console for your project, navigate to *Develop* > *Authentication* > *Sign-in method*
 - Select *Email/Password* and toggle the *Enable* switch
 - Be amazed how easy it was🤯

 **Create a registration form**

 Now that we enabled authentication in Firebase, we need to create a registration form in our app. In order to register we will need an **email** and a **password**.

Create a new component inside the `components` folder and call it `Register.js`.

Since we are using ant design we will import some UI components and firebase from our previous created `Firebase.js`

```js
import React, { Component } from 'react';
import { Card, Col, Row, Form, Input, Button } from 'antd';

import firebase from './Firebase';

class Register extends Component {

}

export default Register;
```

Next let's add a constructor, pass some props and set a state object that will be used for the registration form, along with binding some methods.

```js
	constructor(props) {
		super(props);
		this.state = {
			displayName: '',
			email: '',
			password: '',
			confirmPassword: '',
			errorMessage: null
		}

		this.handleChange = this.handleChange.bind(this);
		this.handleSubmit = this.handleSubmit.bind(this);
	}
```
 Our next step is to create the render method and add a form. For customization we will use some antdesign components:

 ```js
	render() {

		const formItemLayout = {
			labelCol: {
				xs: { span: 24 },
				sm: { span: 4 }
			},
			wrapperCol: {
				xs: { span: 24 },
				sm: { span: 16 }
			}
		}

		return (
			<Row gutter={16}>
				<Col span={12}>
					<Card title="Register" bordered={true}>

						{this.state.errorMessage !== null ? (<div> {this.state.errorMessage} </div>) : null}

						<Form {...formItemLayout} onSubmit={this.handleSubmit}>
							<Form.Item label="Display Name">
								<Input name="displayName" value={this.state.displayName} onChange={this.handleChange} />
							</Form.Item>

							<Form.Item label="Email Address">
								<Input name="email" value={this.state.email} onChange={this.handleChange} />
							</Form.Item>

							<Form.Item label="Password">
								<Input.Password name="password" value={this.state.password} onChange={this.handleChange} />
							</Form.Item>

							<Form.Item label="Confirm Password">
								<Input.Password name="confirmPassword" value={this.state.confirmPassword} onChange={this.handleChange} />
							</Form.Item>

							<Form.Item>
								<Button type="primary" htmlType="submit">
									Register
								</Button>
							</Form.Item>
						</Form>

					</Card>
				</Col>
			</Row>
		);
	}
 ```

 I've left the two methods at the end since we need to explain them in more detail.

  **`handleChange`**

  What we want to accomplish with this method is to grab the values from our form and set in the state object our field value. We also added a check to determine if our two passwords fields match. If they do not match we set an error message that will be displayed at the top of our form.

  ```js
  	handleChange(e) {
		const itemName = e.target.name;
		const itemValue = e.target.value;

		this.setState({ [itemName]: itemValue }, () => {
			if (this.state.password !== this.state.confirmPassword) {
				this.setState({ errorMessage: 'Password do not match!' });
			} else {
				this.setState({ errorMessage: null });
			}
		});
	}
  ```

  **`handleSubmit`**

  Here we want to call the Firebase API to authenticate our user with an email and a password. Since the `createUserWithEmailAndPassword` returns a promise, after the user is registered we call a method passed through props that will log the user in our app(we will add it shortly). We also implemented a catch to handle authentication errors.

  ```js
  handleSubmit(e) {
		const registrationInfo = {
			displayName: this.state.displayName,
			email: this.state.email,
			password: this.state.password
		}

      // Stop the default behaviour of the form
		e.preventDefault();

		// Create a new user with email and password
		firebase.auth().createUserWithEmailAndPassword(registrationInfo.email, registrationInfo.password)
			.then(() => {
				this.props.registerUser(registrationInfo.displayName);
			}).catch(error => {
				if (error.message !== null) {
					this.setState({ errorMessage: error.message });
				} else {
					this.setState({ errorMessage: null });
				}
			});
	}
  ```

  The whole creation of a new user is in this line 
  `firebase.auth().createUserWithEmailAndPassword(email, password)`🤯.
  The rest of the code is added there for error handling and a nicer user experience.

  Now that we finished with our registration component let's go back to our `App.js` file and connect it.

 **But first...** let's install another package 😆

 Enter [Reach Router](https://reach.tech/router). This package will help us navigate through multiple pages with a simple to use API.

 ```
 npm install @reach/router --save
 ```

 With this package installed let's create first a navigation component to quickly change between pages.

 Create a new `Navigation.js` file inside the components folder.

 ```js
import React, { Component } from 'react';
import { Layout, Menu } from 'antd';
import { Link } from '@reach/router';

const { Header } = Layout;

class Navigation extends Component {

	render() {
		const { user, logOutUser } = this.props;
		return (
				<Header>
					<Menu theme="dark" mode="horizontal" defaultSelectedKeys={['1']} style={{ lineHeight: '64px', float: 'right' }} >
						{!user &&
							<Menu.Item key="1">
								<Link to="/login">Log in</Link>
							</Menu.Item>}
						{!user &&
							<Menu.Item key="2">
								<Link to="/register">Register</Link>
							</Menu.Item>}
						{user &&
							<Menu.Item key="3">
								<Link to="/login" onClick={e => logOutUser(e)}>Log out</Link>
							</Menu.Item>}
					</Menu>
				</Header>
		);
	}
}

export default Navigation;
 ```

 This will give us a nice navigation bar. I used the `Link` component from reach router to link our pages. We don't have the login page, yet. I also added a event when the user clicks on the 'Log out' button to be redirected to the login page.

 So let's create a login component.

 As we did before navigate inside the components folder and create a `Login.js` file. 

 The code is similar to the registration page, except this time we will use Firebase API to sign in.

 ```js
 import React, { Component } from 'react';
import { Card, Col, Row, Form, Input, Button } from 'antd';
import { navigate } from '@reach/router';

import firebase from './Firebase';

class Login extends Component {

    constructor() {
        super();
        this.state = {
            email: '',
            password: '',
            errorMessage: null
        }

        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
    }

    handleChange(e) {
        const itemName = e.target.name;
        const itemValue = e.target.value;

        this.setState({ [itemName]: itemValue });
    }

    handleSubmit(e) {
        const loginInfo = {
            email: this.state.email,
            password: this.state.password
        }

        // Prevent the default behaviour of the form
        e.preventDefault();

        // log in user with email and password
        firebase.auth().signInWithEmailAndPassword(loginInfo.email, loginInfo.password)
            .then(() => {
                // Navigate to the root of our app - navigate is a method provided by reach router
                navigate('/');
            }).catch(error => {
                if (error.message !== null) {
                    this.setState({ errorMessage: error.message })
                } else {
                    this.setState({ errorMessage: null });
                }
            });

    }

    render() {
        const formItemLayout = {
            labelCol: {
                xs: { span: 24 },
                sm: { span: 4 }
            },
            wrapperCol: {
                xs: { span: 24 },
                sm: { span: 16 }
            }
        }

        return (

            <Row gutter={16}>
                <Col span={12}>
                    <Card title="Log in" bordered={true}>

                        {this.state.errorMessage !== null ? (<div style={{ color: 'red' }}>{this.state.errorMessage}</div>) : null}

                        <Form {...formItemLayout} onSubmit={this.handleSubmit}>
                            <Form.Item label="Email">
                                <Input name="email" value={this.state.email} onChange={this.handleChange} />
                            </Form.Item>

                            <Form.Item label="Password">
                                <Input.Password name="password" value={this.state.password} onChange={this.handleChange} />
                            </Form.Item>

                            <Form.Item>
                                <Button type="primary" htmlType="submit">
                                    Log in
								</Button>
                            </Form.Item>
                        </Form>

                    </Card>
                </Col>
            </Row>
        );
    }
}

export default Login;
 ``` 

 The most amazing thing is that the login is composed from a single line of code `firebase.auth().signInWithEmailAndPassword(email, password)` 🤯.

 Here we also use another method from the reach router library `navigate()`. In the most simple form it accepts a string. We passed a `/` meaning that we want to go to the root of our app since we want to KISS😏.

 Now we can go to our `App.js` and start making some changes. The first thing that I'm going to do is to transform it to a class and import our registration, navigation and login components, along with firebase and some antdesign stuff.

 First step? Delete all from App.js and replace it with the following:

 ```js
import React, { Component } from 'react';
import { Router, navigate } from '@reach/router';
import firebase from './components/Firebase';

import { Layout } from 'antd';
import './App.css';

import Register from './components/Register';
import Navigation from './components/Navigation';
import Login from './components/Login';

const { Content } = Layout;

class App extends Component {

	constructor() {
		super();
		this.state = {
			user: null,
			displayName: null,
			userID: null
		};
	}

	componentDidMount() {
		// When a user is logged in, get related data
		firebase.auth().onAuthStateChanged(FBUser => {
			if (FBUser) {
				this.setState({
					user: FBUser,
					displayName: FBUser.displayName,
					userID: FBUser.uid
				});

			} else {
				this.setState({ user: null });
			}
		});
	}

	/**
	 * Registers a user using the Firebase api
	 */
	registerUser = userName => {

		// When something changes about authentication, this event gets generated
		firebase.auth().onAuthStateChanged(FBUser => {
			// Push information to firebase
			FBUser.updateProfile({
				displayName: userName
			}).then(() => {

				this.setState({
					user: FBUser,
					displayName: FBUser.displayName,
					userID: FBUser.uid
				});

				navigate('/');
			});
		});
	}

	/**
	 * Logs out the current authenticated user
	 */
	logOutUser = e => {
		e.preventDefault();
		this.setState({
			user: null,
			displayName: null,
			userID: null
		});

		firebase.auth().signOut().then(() => navigate('/login'));
	}

	render() {
		return (
			<React.Fragment>
				<Layout className="layout">
					<Navigation user={this.state.displayName} logOutUser={this.logOutUser} />
					<Content>
						<div style={{ background: '#fff', padding: 24, minHeight: 280 }}>
							{this.state.displayName}
							<Router>
								<Login path="/login" user={this.state.user} />
								<Register path="/register" registerUser={this.registerUser} />
							</Router>
						</div>
					</Content>
				</Layout>
			</React.Fragment>
		);
	}

}

export default App;

 ```

 Whoa... that is a lot. Let's break it down.

 **`constructor`**

 Our first look will be inside the constructor, where we will set the state object for this component with 3 properties(user, displayName and userID).
 When we register a new user, Firebase will generate a User UID composed of random numbers and letters.

 **`componentDidMount`**

 When a user signs in our out we want to update the state of the current user. To do this we will use `firebase.auth().onAuthStateChanged()` that will return a FirebaseUser object if a user is logged in.

 **`registerUser`**

 When we created the Register.js component, after we registered a user we called this method through props. The first part is similar to the `componenentDidMount` method, except that we also update the profile of the user with the displayName and redirect the page to the root of the application. This method gets triggered when we are on the `/register` page.

**`logOutUser`**

This method will sign out a user and then redirect to the `/login` page. We pass this to the navigation component through props. Here we also clear the state of the current user.


 **`render`**

 One of the crazy things about React is that it will only return a single thing. So it forces you to enter a `div` element or other type of container.
 Another solution is `<React.Fragment>`. This will still return a single thing, but the fragment will not be rendered on the page. So you are no longer forced to use a container for your code🙂.


Now we can `npm run start` and test the registration and log in functionality, along with the routing😄.

After you register a user, you can check the Firebase console > *Develop* > *Authentication* > *User* tab in order to see the registered users.

### Conclusion

It feels like we covered a lot in this post. In my next one I will continue this small app and integrate it with a Firebase Realtime DB. I will also explore some advanced routing and custom authorization rules🤗.

### Tips: 
You can install a browser extension called *React Developer Tools* for Firefox and Chrome in order to facilitate debugging. If you are using anything else 😥, download one of these🤣.
 - [Firefox - React Developer Tools](https://addons.mozilla.org/en-US/firefox/addon/react-devtools/)
 - [Chrome - React Developer Tools](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en)