Oct 01 2019
Oct 01, 2019

How to create a Login and Registration form with React.js

Categorised in:

React.js is a JavaScript library for building user interfaces. It is maintained by Facebook and a community of individual developers and companies.

In this article we will use React to create a Login and Registration form. React makes it painless to create interactive UIs. It makes it easy to design simple views for each state in our application, and it efficiently updates and renders just the right components when our data changes.

And because the Log in form is one of the main functionality an app can have we thought that building one in this tutorial would be a good example to demonstrate how React.js works.

To get started let’s install our React.js application by using the following command in Windows OS:

npx creact-react-app react-firebase

While our app is being installed let’s go ahead and configure our Google Firebase Project. Let’s go on firebase.google.com, click on Go to console button and then click on Add project button and follow the three steps instructions:

1. We enter a project name and then click Continue;

Firebase

2. Uncheck Enable Google Analytics and click Create project;

Google Firebase

After we’ve created our project, we click on the settings icon next to the Project Overview tab and then click on Project Settings.

Firebase

Scroll down to our apps and create an app by clicking on the Web Development app as shown in the screenshot below:

Frebase

Here we insert a name and click Create app.

On the next screen we will see all our credentials; we will need to connect our React app to Firebase. Keep this tab open or save this code for later.

On the left sidebar we have a link under the Develop section which is named Authentification. Let’s click on it and then from there let’s click on Set up sign-in method button. Under Sign-in providers let click on Email/Password and then enable it from there and click Save.

Now let’s open our React app and start coding. I am using Visual Studio Code for this tutorial.

Let’s start by installing Firebase in our project’s folder. The command for that is:

npx install --save firebase

After the installation is done, we should start our local machine using the command

npm start

After a new tab is opened in the browser and we see the default page of our React app, we can go ahead and create a Firebase configuration file which will contain all the information for our app to connect to Firebase (You can find a link to the full source code at the end of the article).

In the src folder let’s create another folder -- “config” -- and then in this folder let’s create a “Fire.js” file. We’ll use the code below with the credentials we’ve got when we created our Web app in our Google Firebase Dashboard. We start by importing Firebase and then exporting the whole object at the end of the file.

import firebase from 'firebase';

const config = {
    apiKey: "",
    authDomain: "",
    databaseURL: "",
    projectId: "",
    storageBucket: "",
    messagingSenderId: "",
    appId: ""
};

const fire = firebase.initializeApp(config);
export default fire;

The next step is to create another folder in in the src folder and name it “components”. In this folder we will create a new file: “LoginRegister.js”. At the top of this file we will import React and the configuration file:

import React, {Component} from 'react';
import fire from '../config/Fire';

This component will be a Class Component, and we will have a constructor where the state for this object will be:

class Login extends Component {
    constructor(props){
        super(props);
        this.state = {
            email: '',
            password: '',
            fireErrors: '',
            formTitle: 'Login',
            loginBtn: true
        }
    }

email: will store the email from the Login Form;
password: will store the password form the Login Form;
fireErrors: will store all the notifications Firebase will return whenever somebody tries to log in. Usually these notifications are returned whenever the user inserts an incorrect email or password;
formTitle: is the title above the form fields. See screenshot below;

Login Form

loginBtn: will change its value according the button the user clicked on.

Below the constructor, we will have two other methods: login and register:

login = e => {
	e.preventDefault();
	fire.auth().signInWithEmailAndPassword(this.state.email, this.state.password)
	.catch((error) => {
		this.setState({fireErrors: error.message})
	});
}

register = e => {
	e.preventDefault();
	fire.auth().createUserWithEmailAndPassword(this.state.email, this.state.password)
	.catch((error) => {
		this.setState({fireErrors: error.message})
	});
}

We will call these methods whenever the user clicks on the Login or Register Button.

fire.auth().signInWithEmailAndPassword and fire.auth().createUserWithEmailAndPassword are functions we call from the Firebase library we installed at the beginning.

The form title and the submit button will change depending on which button the user clicks. The next step is to create a method which will handle this action for us. We will name it getAction:

getAction = action => {
	if(action === 'reg'){
		this.setState({formTitle: 'Register New User', loginBtn: false, fireErrors: ''});
	}else{
		this.setState({formTitle: 'Login', loginBtn: true, fireErrors: ''});
	}
}

A handleChamnge method is also required because it will handle the information the user is writing in the email and the password fields.

handleChange = e => {
	this.setState({[e.target.name]: e.target.value});
}

Having all of this in place, now it is time for the render function. In the render function, we will have most of the conditional logic which will call the methods from the above.

render(){

	let errorNotification = this.state.fireErrors ? 
		( <div className="Error"> {this.state.fireErrors} </div> ) : null;

Here we have an if statement which checks if the fireErrors state contains any data, then we assign it to the errorNotification variable. This variable will be added above the email and password field.

let submitBtn = this.state.loginBtn ? 
(<input className="loginBtn" type="submit" onClick={this.login} value="Enter" />) : 
(<input className="loginBtn" type="submit" onClick={this.register} value="Register" />);

The submitBtn is the variable which will store the submit button and it will be added below the email and the password field.

let login_register = this.state.loginBtn ?
	(<button className="registerBtn" onClick={() => this.getAction('reg')}>Register</button>) : 
	(<button className="registerBtn" onClick={() => this.getAction('login')}>Login</button>)

Next to submitBtn we will have another button which will allow us to switch from the Login to the Register form and vice versa. We are using onClick event to call the getAction method with a corresponding parameter.

Now it’s time to create the return function where we will write the JSX code with all the variables created above.

        return(
            <div className="form_block">
                <div id="title">{this.state.formTitle}</div>
                <div className="body">
                    {errorNotification}
                    <form>
                        <input type="text" 
                        value={this.state.email} 
                        onChange={this.handleChange} 
                        name="email" />

                        <input type="password" 
                        value={this.state.password} 
                        onChange={this.handleChange} 
                        name="password" />

                        {submitBtn}
                    </form>
                    {login_register}
                </div>
            </div>
        )
    }
}

So the whole file needs to look like this:

import React, {Component} from 'react';
import fire from '../config/Fire';

class Login extends Component {
    constructor(props){
        super(props);
        this.state = {
            email: '',
            password: '',
            fireErrors: '',
            formTitle: 'Login',
            loginBtn: true
        }
    }

    login = e => {
        e.preventDefault();
        fire.auth().signInWithEmailAndPassword(this.state.email, this.state.password)
        .catch((error) => {
            this.setState({fireErrors: error.message})
        });
    }

    register = e => {
        e.preventDefault();
        fire.auth().createUserWithEmailAndPassword(this.state.email, this.state.password)
        .catch((error) => {
            this.setState({fireErrors: error.message})
        });
    }

    getAction = action => {
        if(action === 'reg'){
            this.setState({formTitle: 'Register New User', loginBtn: false, fireErrors: ''});
        }else{
            this.setState({formTitle: 'Login', loginBtn: true, fireErrors: ''});
        }
    }

    handleChange = e => {
        this.setState({[e.target.name]: e.target.value});
    }

    render(){

        let errorNotification = this.state.fireErrors ? 
            ( <div className="Error"> {this.state.fireErrors} </div> ) : null;

        let submitBtn = this.state.loginBtn ? 
            (<input className="loginBtn" type="submit" onClick={this.login} value="Enter" />) : 
            (<input className="loginBtn" type="submit" onClick={this.register} value="Register" />);

        let login_register = this.state.loginBtn ?
            (<button className="registerBtn" onClick={() => this.getAction('reg')}>Register</button>) : 
            (<button className="registerBtn" onClick={() => this.getAction('login')}>Login</button>)

        return(
            <div className="form_block">
                <div id="title">{this.state.formTitle}</div>
                <div className="body">
                    {errorNotification}
                    <form>
                        <input type="text" 
                        value={this.state.email} 
                        onChange={this.handleChange} 
                        name="email" />

                        <input type="password" 
                        value={this.state.password} 
                        onChange={this.handleChange} 
                        name="password" />

                        {submitBtn}
                    </form>
                    {login_register}
                </div>
            </div>
        )
    }
}

export default Login;

After we are done with this file, we should create another one in the same folder and call it “Home.js”. This file will output the content the users will see after they log in.

We will have just a simple class with a Logout button:

import React, {Component} from 'react';
import fire from '../config/Fire';

class Home extends Component {

    logout = () => {
        fire.auth().signOut();
    }

    render(){
        return(
            <div>
                <h1>You are home!</h1>
                <button onClick={this.logout}>Logout</button>
            </div>
        )
    }
}

export default Home;

So, after all of this is done, our App.js file will look like this:

import React, {Component} from 'react';
import fire from './config/Fire';
import Login from './components/LoginRegister';
import Home from './components/Home';
import './App.css';

class App extends Component {

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

  componentDidMount(){
    this.authListener();
  }

  authListener(){
    fire.auth().onAuthStateChanged((user) => {
      if(user){
        this.setState({user});
      }else{
        this.setState({user:null});
      }
    });
  }

  render(){
    return (
        <div>
          {this.state.user ? (<Home />) : (<Login />)}
        </div>
    );
  }
}

export default App;

We import React, LoginRegister, Home and the configuration file Fire.js. After that we have our constructor, where we store the state. In the state, we save the user data received from Firebase.

componentDidMount is calling the authListener method which updates the state depending on if the user is logged in or not. In the render function, we call either the Home or the LoginRegister component, depending on the data we have in the state. If the state is empty, it means that we didn’t receive any user data from Firebase, which means that the user is not logged in.

The last step is the CSS code. Let’s open the App.css file, and let’s replace everything from it with the following code:

.form_block{
  width: 400px;
  display: table;
  margin-top: 10%;
  margin-left: auto;
  margin-right: auto;
  background-color: rgba(0,0,0,.1);
  padding: 5px;
  border-radius: 5px;
}
.form_block > #title{
  background: #3d8577;
  padding: 10px;
  color: #fff;
  font-weight: bold;
  font-size: 20px;
  text-align: center;
  border-top-right-radius: 5px;
  border-top-left-radius: 5px;
  text-shadow: -1px -1px 0 rgba(0,0,0,.2);
}
.form_block > .body{
  background: #FFFFFF;
  padding: 10px;
  display: table;
}

input[type='text'],input[type='password'] {
  height: 35px;
  width: 100%;
  margin-bottom: 10px;
  box-sizing: border-box;
  padding: 4px 5px;
  background: #fff;
  border: 1px solid #d0d0d0;
  -webkit-border-radius: 3px;
  -moz-border-radius: 3px;
  border-radius: 3px;
}
.loginBtn{
  height: 35px;
  box-sizing: border-box;
  padding: 4px 10px;
  background: #f5f4ea;
  border: 1px solid #d0d0d0;
  -webkit-border-radius: 3px;
  -moz-border-radius: 3px;
  border-radius: 3px;
  cursor: pointer;
}
.loginBtn:hover{
  background: #c3c3ba;
}
.registerBtn{
  float: right;
  background: #3d8577;
  color: #fff;
  height: 35px;
  box-sizing: border-box;
  padding: 4px 10px;
  border: 1px solid #d0d0d0;
  -webkit-border-radius: 3px;
  -moz-border-radius: 3px;
  border-radius: 3px;
  cursor: pointer;
  margin-top: -35px;
}
.registerBtn:hover{
  background: #2d6358;
}
.Error{
  padding: 10px;
  background-color: #feeaea;
  border: 1px solid #fadadb;
  margin-bottom: 10px;
  border-radius: 3px;
}

Now our app should work perfectly fine.

In this article we had the chance to work with a lot of new concepts. First we learned how to create a Firebase project, how to connect our app and how to use the Firebase library.

Make sure to check the resources bellow as we didn’t get into much details about the functions we used in our project.

You can also watch the video version of this tutorial on youtube: Click Here!

Keep on coding!

Source code:
https://github.com/ruvictor/react-firebase

Resources:
1.
https://reactjs.org/
2. https://firebase.google.com/docs
3. https://www.npmjs.com/