Login - Part 5

This video is available to view for members only.

Click here to Join!

Already a member?

Login


In this video we are going to handle the last major step in the Login journey: Updating our application state.

This is where the term "Reducer" comes into play.

The reducer / reducing function is something we need to code.

We will start by defining a function which gets given state as it's first argument, and an action is its only other argument.

The convention I'm following is that whatever name this function has will serve as the key for this part of the next resulting application state:

// /src/reducers/authReducer.js

import * as types from '../constants/actionTypes';

export default function auth(state = {
  isAuthenticated: false,
  id: undefined,
  username: undefined
}, action) {

  switch (action.type) {

    case types.LOGIN__COMPLETED: {
      const { id, username } = action.payload;
      return Object.assign({}, state, {
        isAuthenticated: true,
        id,
        username
      })
    }

    case types.LOGOUT__COMPLETED: {
      return Object.assign({}, state, {
        isAuthenticated: false,
        id: undefined,
        username: undefined
      })
    }
  }
}

In the video we work through the understanding of how the function comes into being.

A really nice JavaScript ES6 method used in this code is Object.assign. By taking an empty object {} as our target, we can pass in one or more objects to the final object. Seeing code makes this easier to see:

    const o1 = { a: 1, b: 1, c: 1 };
    const o2 = { b: 2, c: 2 };
    const o3 = { c: 3 };

    let outcome = Object.assign(o1, o2, o3);

    assert.deepEqual(outcome, { a: 1, b: 2, c: 3 }); // true

And this is fine, but be careful here as in this instance, o1 would have been changed.

    let outcome = Object.assign(o1, o2, o3);

    assert.deepEqual(outcome, { a: 1, b: 2, c: 3 });

    console.log(o1); // Object {a: 1, b: 2, c: 3}

So, to stop this, the first parameter is set to be an empty object:

    let outcome = Object.assign({}, o1, o2, o3);

    assert.deepEqual(outcome, { a: 1, b: 2, c: 3 });

    console.log(o1); // Object {a: 1, b: 1, c: 1}

In our case, that's going to give us the next state being whatever the current state is, but with only the subset of changes (action.payload) we want applying.

We also add in the isAuthenticated boolean value, giving ourselves a handy shortcut to checking if the user is or is not logged in. You could do this differently by using Redux selectors (e.g. reselect), but I don't need anything that fancy at this stage.

Also, I've added in the inverse for LOGOUT_COMPLETED - unsetting stuff, and generally cleaning up. We don't immediately need that, but doing it now will save us a job in the future.

You must remember to add your new reducer into the list of reducers that Redux will be aware of:

// /src/reducers/index.js

import {combineReducers} from 'redux';
import {routerReducer} from 'react-router-redux';
import {reducer as formReducer} from 'redux-form';
import auth from './authReducer';

const rootReducer = combineReducers({
  form: formReducer,
  routing: routerReducer,
  auth,
});

export default rootReducer;

And with that we can define a mapStateToProps function, which when passed into Redux connect() allows us to augment our component's props with interesting parts of our application's state.

function mapStateToProps(state) {
  return {
    auth: state.auth
  }
}

export default connect(
  mapStateToProps
)(App);

And then inside our component's render method, we could use this prop:

render() {
    return (
        {this.props.auth.isAuthenticated ? 'Welcome back!' : 'You must login'}
    )
}

We will do something like this shortly, when adding a Bootstrap Navbar to our UI.


Code For This Course

Get the code for this course.

Code For This Episode

Get the code for this episode.

Share This Episode

If you have found this video helpful, please consider sharing. I really appreciate it.


Episodes in this series

# Title Duration
1 App Walkthrough - User Experience 03:15
2 App Walkthrough - Developer Experience 07:41
3 Development Environment Setup 06:34
4 Login - Part 1 09:15
5 Login - Part 2 07:55
6 Login - Part 3 12:37
7 Login - Part 4 10:22
8 Login - Part 5 08:00
9 Saving Redux State to Local Storage 08:50
10 Logout 10:57
11 Adding an Auth-aware NavBar 14:43
12 Cleanup, Linting, and Login Form Styling 09:58
13 Showing Spinning Icons, Because Why Not? 08:11
14 More Robust Request Tracking 09:07
15 Getting Started Testing With Jest 06:43
16 Testing Request Reducer - Part 1 11:35
17 Testing Request Reducer - Part 2 05:25
18 Testing AuthSaga - Happy Path 09:19
19 Testing AuthSaga - Unhappy Paths 04:38
21 Testing JavaScript's Fetch with Jest - Happy Path 05:15
21 Testing JavaScript's Fetch with Jest - Unhappy Paths 04:35
22 Getting Started with Jest Mocks 08:52
23 Using Webpack Environment Variables in Jest Tests 09:37
24 User Profile Page - Part 1 07:31
25 User Profile Page - Part 2 10:25
26 User Profile Page - Part 3 07:23
27 Change Password - Part 1 10:01
28 Change Password - Part 2 07:59
29 Change Password - Part 3 - Displaying Errors 06:28
30 Change Password - Part 4 - Converting Errors From Symfony to Redux Form 05:39
31 Change Password - Part 5 - Adding More Tests 05:06
32 Change Password - Part 6 - Avoid Blocking, and Wrap Up 06:23
33 Registration - Part 1 08:50
34 Registration - Part 2 06:25
35 Registration - Part 3 05:25