An Introduction to React & Redux (Part 4)

I’ve been investigating Redux recently. If you missed the first three parts:

Thus far, my application is simple. I have some authentication related tasks and a UI related task. It’s currently no problem that all the state, actions and reducers are intermingled. However, this will become a problem as I move forward – more state elements and more actions will mean that I can’t rely on a flat structure. Today, I’m going to create two parts to my store – an auth section and a UI section.

Step 1: Set up action constants

As I grow, I will want to ensure that my action types are all unique, but still give a naming scheme that makes sense. To ensure this happens, I am going to use a separate constants.js file:

export default {
    ui: {
        leftMenuVisibility: 'ui.leftMenuVisibility'
    auth: {
        setAnonymous: 'auth.setAnonymous',
        setAuthenticated: 'auth.setAuthenticated',
        setError: 'auth.setError'

I’ve just made the string equal to the object path (or how I would access that string). This means that logging functions will display something reasonable. I, of course, need to update all the action creators:

import constants from './constants';

 * Redux Action Creator for toggling left menu visibility
 * @param {bool} open the requested state of the left menu
 * @returns {Object} Redux Action
export function displayLeftMenu(open) {
    return {
        type: constants.ui.leftMenuVisibility,
        visibility: open

Repeat with all the action creators.

Step 2: Split up the Reducers

I’ve got a reducers.js file right now. I want to split them up. Create a reducers directory. The reducers/ui.js file will contain the reducer for the UI actions:

import constants from '../constants';

const initialState = {
    leftMenuVisibility: false

 * Redux Reducer for UI manipulation
 * @param {Object} state the initial state
 * @param {Object} action the Redux Action object
 * @returns {Object} the new state
export default function uiReducer(state = initialState, action) {
    if (action.type === constants.ui.leftMenuVisibility) {
        return Object.assign({}, state, {
            leftMenuVisibility: action.visibility
    return state;

There are two things to note here. Firstly, the uiReducer only handles the state for the UI. Secondly, I am using an ES2015 default parameter to set the state of the UI and that only includes the state of the UI. Similarly, the reducers/auth.js only handles authentication:

import constants from '../constants';

const initialState = {
    phase: 'pending',
    user: null,
    error: null

export default function authReducer(state = initialState, action) {
    switch (action.type) {
    case constants.auth.setAnonymous:
        return Object.assign({}, state, {
            phase: 'anonymous',
            user: null,
            error: null

    case constants.auth.setAuthenticated:

        let claims = action.providerInfo.user_claims.reduce((target, claim) => {
            target[claim.typ] = claim.val;
            if (claim.typ.indexOf('') !== -1)
                target[claim.typ.slice(claim.typ.lastIndexOf('/') + 1)] = claim.val;
            return target;

        let user = {
            accessToken: action.providerInfo.access_token,
            claims: claims,
            givenname: claims.givenname || '',
            name: || '',
            id: action.providerInfo.user_id,
            provider: action.providerInfo.provider_name,
            providerToken: action.providerInfo.authentication_token,
            surname: claims.surname || ''

        return Object.assign({}, state, {
            phase: 'authenticated',
            user: user,
            error: null

    case constants.auth.setError:
        return Object.assign({}, state, {
            phase: 'error',
            user: null,
            error: action.error.message

        return state;

I need to bring these together, so I’ve created a reducers/index.js with the following contents:

import ui from './ui';
import auth from './auth';

module.exports = {
    auth: auth,
    ui: ui

Don’t forget to remove reducers.js so that the new stuff is imported when you import ./reducers.

Step 3: Update the Store to combine reducers

I’ve updated the action creators to use constants, then split the reducers. Now I need to combine the reducers. Here are the updates to the redux/store.js file:

import { createStore, combineReducers, applyMiddleware } from 'redux';
import createLogger from 'redux-logger';
import rdxThunk from 'redux-thunk';
import rdxPromise from 'redux-promise';
import { requestAuthInfo } from './actions';
import * as reducers from './reducers';

// Combine the reducers for the store
const appReducers = combineReducers(Object.assign({},

// Create the Redux Store
const store = reduxStore(
    applyMiddleware(rdxThunk, rdxPromise, createLogger())

// Dispatch the initial action

export default store;

The important pieces here are the reducers. In line 6, I’m importing all the reducers that are exported via reducers/index.js. Lines 9-11 then combine all those reducers into one. Note that the initialState has been moved to the reducers – this allows each reducer file to handle its own state.

Step 4: Update the Component Views

Things will breack pretty dramatically if you run this project. However, running it will give you an idea of the new structure of the store. It’s now a heirarchy:

    "auth": { "error": null, "phase": "anonymous", "user": null },
    "ui": { "leftMenuVisibility": false }

The component views need to compensate for this new store format. This is mostly done in the propTypes object plus the connect call. Here are the new propTypes for components/Chrome.jsx:

    static propTypes = {
        auth: React.PropTypes.shape({
            error: React.PropTypes.string,
            phase: React.PropTypes.string.isRequired,
            user: React.PropTypes.object
        children: React.PropTypes.node,
        dispatch: React.PropTypes.func.isRequired,
        ui: React.PropTypes.shape({
            leftMenuVisibility: React.PropTypes.bool.isRequired

Note that I’ve described the auth and ui store properties precisely. I also need to update the connect() call:

export default connect(
    (store) => {
        return {
            auth: store.auth,
            ui: {
                leftMenuVisibility: store.ui.leftMenuVisibility

I am probably not going to add more fields to the auth store, but I am extremely likely to add things to the ui store. As a result, I’ve described precisely what I need in the component. This matches what I’ve done in the propTypes. All I need to do once this is done is alter the references within the compoennt to the right props. For example, this.props.phase becomes this.props.auth.phase.

Wrap Up

This may seem like a small change and unnecessary complication right now, but organization is important as the application grows and this puts me on the appropriate track. I’m also splitting up the action creators in the same way. That allows me to expand the Redux store as required.

You can find the latest code at my GitHub Repository. Want to check out the differences? Just compare to the prior commit:

git diff 2016-03-01 2016-03-04

This will give you all the differences. You can compare this release to the prior one on the github repository by clicking here.