Creating a login form with React for authentication

As we have done with the authentication configuration for Firebase and Facebook and enabled the features for other providers, now we'll create a login form in react to secure the application that always validates whether the user logged in or not; it will redirect the user to the login page. So let's create a login page and also configure the React routing to redirect he user based on the path URL.

Open firebase-config.js from the firebase folder and export the following objects with different providers so that we can access those objects across the application:

export const firebaseApp = firebase.initializeApp(config);
export const googleProvider = new firebase.auth.GoogleAuthProvider();
export const facebookProvider = new firebase.auth.FacebookAuthProvider();

In the preceding code, new firebase.auth.GoogleAuthProvider() will provide us with the way to authenticate the user to Google API.

Similarly, new firebase.auth.FacebookAuthProvider() will provide us with the way to authenticate the user with Facebook API.

Open app.js and add the following code into constructor to initialize the state of the application:

constructor() {
super();
this.state = {
authenticated : false,
data:''
}
}

Here, we set the default value of authenticated to be false, because it's the initial state of the application and the user has not yet authenticated with Firebase; the default value of data is empty on the initial state of the component. We will change those states as the user logs in.

First, let's create the Login component in login.js and set the initial state of that component in constructor():

 constructor() {
super();
this.state = {
redirect: false
}
}

We have set the default value of redirect false on the initial state, but that will change whenever a user logs in and out:

if(this.state.redirect === true){
return <Redirect to = "/" />
}
return (
<div className="wrapper">
<form className="form-signin" onSubmit={(event)=>{this.authWithEmailPassword(event)}} ref={(form)=>{this.loginForm = form}}>
<h2 className="form-signin-heading">Login</h2>
<input type="email" className="form-control" name="username" placeholder="Email Address" ref={(input)=>{this.emailField = input}} required />
<input type="password" className="form-control" name="password" placeholder="Password" ref={(input)=>{this.passwordField = input}} required />
<label className="checkbox">
<input type="checkbox" value="remember-me" id="rememberMe" name="rememberMe"/> Remember me
</label>
<button className="btn btn-lg btn-primary btn-block btn-normal" type="submit">Login</button>
<br/>
<!-- Here we will add the buttons for google and facebook authentication
</form>
</div>
);

In the render method, we will check the state and redirect the user to a different route <Redirect>. It will override the current route in the history stack, like server-side redirects (HTTP 3xx) do.

Here's a list of attributes that we can use with the Redirect component:

  • to:String: A redirect URL that we have also used.
  • to:Object: A location URL with parameters and other configs, such as state. Consider this example:
<Redirect to={{
pathname: '/login',
search: '?utm=your+selection',
state: { referrer: currentLocation }
}}/>
  • : bool: When it's true, redirecting will push a new entry onto the history instead of replacing the current one.
  • from: string: A URL to redirect from the old URL. This can only be used to match a location inside of a <Switch>. Consider this example:
<Switch>
<Redirect from='/old-url' to='/new-url'/>
<Route path='/new-url' component={componentName}/>
</Switch>
All the preceding <Redirect> features are only available in React Router V4.

We have added the JSX for our login form and bound the methods and ref attribute to access the form values. We have also added the buttons for Facebook and Google authentication. Just look at the following code:

 <!-- facebook button that we have bind with authWithFacebook()-->
<button className="btn btn-lg btn-primary btn-facebook btn-block" type="button" onClick={()=>{this.authWithFacebook()}}>Login with Facebook</button>
<!-- Google button which we have bind with authWithGoogle()-->
<button className="btn btn-lg btn-primary btn-google btn-block" type="button" onClick={()=>{this.authWithGoogle()}}>Login with Google</button>

In app.js, we have configured a router like this:

<Router>
<div className="container"> {
this.state.authenticated
?
(
<React.Fragment>
<Header authenticated = {this.state.authenticated}/>
<Route path="/" render={() => (<Home userInfo = {this.state.data} />)} />
<Route path="/view-ticket" component={ViewTicketTable}/>
<Route path="/add-ticket" component={AddTicketForm}/>
</React.Fragment>
)
:
(
<React.Fragment>
<Header authenticated = {this.state.authenticated}/>
<Route exact path="/login" component={Login}/>
</React.Fragment>
)
}
</div>
</Router>

In the preceding code, we are using React Router version 4, which is a fully rewritten router for react package. In the previous version of React router, they have used a very difficult configuration, which will be difficult to understand, and also, we need to create a separate component to manage the layout. In Router V4, everything works as a component.

In React router V4, we need to import from react-router-dom, not from react-router, as we do in V3. The <Router> component and all other subcomponents get rendered if the route path matches.

Using the <React.Fragment> tag, we can wrap any JSX component without adding another node into the DOM.

In V4 react router, there is no more <IndexRoute>; using <Route exact> will do the same thing.

Now we'll change the header component where we have navigation and add the link to login and logout:

class Header extends Component {
render() {
return (
<div className="navbar navbar-inverse firebase-nav" role="navigation">
{
this.props.authenticated
?
(
<React.Fragment>
<ul className="nav navbar-nav">
<li className="active"><Link to="/">Home</Link></li>
<li><Link to="/view-ticket">Tickets</Link></li>
<li><Link to="/add-ticket">Add new ticket</Link></li>
</ul>
<ul className="nav navbar-nav navbar-right">
<li><Link to="/logout">Logout</Link></li>
</ul>
</React.Fragment>
):(
<React.Fragment>
<ul className="nav navbar-nav navbar-right">
<li><Link to="/login">Register/Login</Link></li>
</ul>
</React.Fragment>
)
}
</div>
);
}
}

It's necessary to use this if we are working with the React router. Let's add <link> in our navigation instead of the <a> tag and replace the href attribute with to. In V4, we can also use <NavLink>; it works the same as <Link>, but gives us the way to add extra styling. Look at this code:

<li><NavLink to="/view-ticket/" activeClassName="active" activeStyle={{fontWeight: 'bold', color: red'}} exact strict>Tickets</NavLink></li>

Based on the authentication, we'll update the navigation with login and a logout link.

Start the server again by running the following command in Command Prompt:

npm start

Once your server is started, open the browser and take a quick look:

If you just take a look at the preceding screen excerpt and note the address bar, I have tried to open another URL to view the tickets, but it's not showing anything except header login link; so now, if we click on Login, it will render the login form. Refer to the following screenshot; it should look like this:

It's amazing that our login form looks great, as expected.

For more information about react router, you can go through https://reacttraining.com/react-router/web/api.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset