Home » React » Login flow with React and Redux

Login flow with React and Redux


I have created a live coding version for this tutorial. Check it at here: https://youtu.be/MdeqXWo4fOI

Login is usually the first page we have to build in almost any app. In this tutorial, we will build a interactive and intuitive login form with React & Redux.

Here are some features of our login form:

  • It has an email field and a password
  • When user clicks submit, it will show a message to indicate that it is sending request to server.
  • When receiving response, it will show login status.

An ugly wild login form appears 🙂

Prerequisite libraries

  • create-react-app: I always use this library to create my React project, it will install React and some scripts with make our React app running
  • redux: our state management
  • redux-thunk: we use this library to compose some actions and create flow for login
  • redux-logger: this library logs every changes to Redux store

Application state

Because we only have a login form, our application state is pretty simple, it has 3 attributes:

  • isLoginPending: indicates when login has sent login request
  • isLoginSuccess: indicates if login successful
  • loginError: contains the error message if login fail

Let’s create some actions for these attributes


function setLoginPending(isLoginPending) {
  return {

function setLoginSuccess(isLoginSuccess) {
  return {

function setLoginError(loginError) {
  return {
    type: SET_LOGIN_ERROR,

Simulating login request

Here is the source code to simulating our login request. We provide email, password and a callback. If email and password are correct, it will call the callback and pass a null parameter. Otherwise, it will pass an error object.

function callLoginApi(email, password, callback) {
  setTimeout(() => {
    if (email === 'admin@example.com' && password === 'admin') {
      return callback(null);
    } else {
      return callback(new Error('Invalid email and password'));
  }, 1000);

Compose actions together

Now we can write an action to actual send login request and dispatch our actions!

export function login(email, password) {
  return dispatch => {

    callLoginApi(email, password, error => {
      if (!error) {
      } else {

So when this action is dispatched, it set login pending status to true, login success to and login error to null. After that it calls our simulated login api.

The reducer

Here is the function that actually makes change to our Redux store

export default function reducer(state = {
  isLoginSuccess: false,
  isLoginPending: false,
  loginError: null
}, action) {
  switch (action.type) {
      return Object.assign({}, state, {
        isLoginPending: action.isLoginPending

      return Object.assign({}, state, {
        isLoginSuccess: action.isLoginSuccess

      return Object.assign({}, state, {
        loginError: action.loginError

      return state;

Nothing is complicated at here

UI component

Here is the login form. In practice, we should separate this component into smart and dump components. But for our tutorial, this is enough.

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { login } from '../../redux/reducer';
import './LoginForm.css';

class LoginForm extends Component {

  constructor(props) {
    this.state = {};
    this.onSubmit = this.onSubmit.bind(this);

  render() {
    let {email, password} = this.state;
    let {isLoginPending, isLoginSuccess, loginError} = this.props;
    return (
      <form name="loginForm" onSubmit={this.onSubmit}>
        <div className="form-group-collection">
          <div className="form-group">
            <input type="email" name="email" onChange={e => this.setState({email: e.target.value})} value={email}/>

          <div className="form-group">
            <input type="password" name="password" onChange={e => this.setState({password: e.target.value})} value={password}/>

        <input type="submit" value="Login" />

        { isLoginPending && <div>Please wait...</div> }
        { isLoginSuccess && <div>Success.</div> }
        { loginError && <div>{loginError.message}</div> }

  onSubmit(e) {
    let { email, password } = this.state;
    this.props.login(email, password);
      email: '',
      password: ''

const mapStateToProps = (state) => {
  return {
    isLoginPending: state.isLoginPending,
    isLoginSuccess: state.isLoginSuccess,
    loginError: state.loginError

const mapDispatchToProps = (dispatch) => {
  return {
    login: (email, password) => dispatch(login(email, password))

export default connect(mapStateToProps, mapDispatchToProps)(LoginForm);

In this component, we connect our application to Redux store. Mapping isLoginPending, isLoginSuccess and loginError to the form. These attributes will indicate form status.

When form is submitted, it takes email and password from from and dispatchs the login action.

That’s our login form with React and Redux. In real app, you usually do something more like: store login token to Redux store after login success or redirect to homepage. I guess these things are too easy for you now 🙂

You can grab the source code at here: https://github.com/davidtran/react-redux-login-flow

Let me know if you have any question.