Login page reducer

We've already discussed what a reducer is and what it does. In this section, we are simply going to set up a reducer for login. Create a reducer.js file inside app/containers/App. Since we are dealing with immutable JS, as discussed in Chapter 2, Testing:

import { fromJS } from 'immutable';
import Cookie from 'js-cookie';

import {
LOGIN_REQUEST,
LOGIN_SUCCESS,
LOGIN_FAILURE,
LOGOUT_REQUEST,
} from 'containers/Login/constants';

// The initial state of the App
const initialState = fromJS({
loading: false,
currentUser: {},
});

function appReducer(state = initialState, action) {
switch (action.type) {
case LOGIN_FAILURE:
case LOGIN_REQUEST:
case LOGOUT_REQUEST: {
Cookie.remove('token');
return state.set('loading', true).set('currentUser', fromJS({}));
}
case LOGIN_SUCCESS:
Cookie.set('token', action.user.token, { expires: 7 });
return state.set('loading', true).set('currentUser', fromJS(action.user));
default:
return state;
}
}

export default appReducer;

This is pretty straightforward, right. The appReducer function takes state and action. Based on different action types, it changes the state if required. There are two cases of this as follows:

  • In the case of a login request, or failure, or logout request, we are going to remove any cookie that is stored. Read more about JavaScript cookies here: https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie
  • In the case of login success, we are going to store the token and expiration time in the cookie and return the state with the current user returned from the API request. 

Now, having the reducer defined, we need to connect this reducer to the root reducer inside the main reducers.js file. The main reducer file should look like the snippet given as follows. The changed code is rendered in bold to easily understand what has been added:

import { combineReducers } from 'redux-immutable';
import { connectRouter } from 'connected-react-router/immutable';
import { reducer as formReducer } from 'redux-form/immutable';

import history from 'utils/history';
import globalReducer from 'containers/App/reducer';

export default function createReducer(injectedReducers = {}) {
const rootReducer = combineReducers({
form: formReducer,
global: globalReducer,
...injectedReducers,
});

const mergeWithRouterState = connectRouter(history);
return mergeWithRouterState(rootReducer);
}

We're going to add multiple reducers based on each container and requirement. The idea is very much the same. We create the reducers file in each container, and connect them in the main container. In addition to having each reducer in the same file, we can also use HPF to inject reducer in a component. The function to inject the reducer in the container component is given in app/utils/injectReducer.js, as follows:

import React from 'react';
import PropTypes from 'prop-types';
import hoistNonReactStatics from 'hoist-non-react-statics';

import getInjectors from './reducerInjectors';

export default ({ key, reducer }) => WrappedComponent => {
class ReducerInjector extends React.Component {
static WrappedComponent = WrappedComponent;

static contextTypes = {
store: PropTypes.object.isRequired,
};

static displayName = `withReducer(${WrappedComponent.displayName ||
WrappedComponent.name ||
'Component'})`;

componentWillMount() {
const { injectReducer } = this.injectors;

injectReducer(key, reducer);
}

injectors = getInjectors(this.context.store);

render() {
return <WrappedComponent {...this.props} />;
}
}

return hoistNonReactStatics(ReducerInjector, WrappedComponent);
};

To learn more about how the injectReducer function works, check the file. In a nutshell, the factory higher-order reducer function takes the key and path to reducer file and injects to the wrapping component. In order to copy non-react specific statics from a child component to a parent component, the function uses hoistNonReactStatics from hoist-non-react-statics.

You can read more about hoist-non-react-statics and how it works from the main documentation site provided here: https://github.com/mridgway/hoist-non-react-statics

You can file other associated files, such as reducerInjectors.js, from the GitHub repository. If you check the code inside this file, you will understand that the idea is to inject the reducer to the main reducers so as combine all the reducers in one place. 

..................Content has been hidden....................

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