Introduction to Multiple Reducer in Redux

Introduction

In the previous article, we have learned about the core concepts of Redux along with its implementation. Now in this article, we will be learning about various function provided by Redux library with its importance and usage.

Multiple Reducers

Redux has the pattern of a single store principle to maintain one immutable store. But it is also having the concept of multiple reducers.

Multiple reducer concept is to handle single functionality per reducer.

For example, we have 2 reducers, one is to manage user login and others to update user details

So, updating my index.js code as below,

const redux = require('redux')  
  
console.log("Index js in redux app")  
const LOGIN = 'LOGIN'  
const USER_DETAIL = 'USER_DETAIL'  
// action  
function loggedIn(user, pwd) {  
    return {  
        type: LOGIN,  
        username: user,  
        password: pwd,  
        loggedInStatus: ""  
    }  
}  
function updateUserName(FirstName,LastName,UserName){  
    return{  
        type:USER_DETAIL,  
        FirstName : FirstName,  
        LastName:LastName,  
        UserName:UserName  
    }  
}  
  
function callLoginApi(username, password) {  
    if (username === 'admin' && password === 'admin') {  
        return "Login Success";  
    } else {  
        return 'Invalid email and password';  
    }  
}  
  
const initialState = {  
    username: "test",  
    password: "test",  
    loggedInStatus: "",  
    FirstName : "",  
    LastName : "",  
    UserName :""  
}  
  
const reducer = (state = initialState, action) => {  
    switch (action.type) {  
        case LOGIN:  
            return {  
                ...state,  
                username: action.username,  
                password: action.password,  
                loggedInStatus: callLoginApi(action.username, action.password)  
            }  
        case USER_DETAIL:  
            return {  
                ...state,  
                FirstName: action.FirstName,  
                LastName: action.LastName,  
                UserName: action.UserName  
            }  
        default:  
            return state  
    }  
}  
  
const store = redux.createStore(reducer)  
console.log("Initial State", store.getState())  
const unsubscribe = store.subscribe(() => console.log('Updated state', store.getState()))  
store.dispatch(loggedIn("user", "user"))  
store.dispatch(loggedIn("testing", "testing"))  
store.dispatch(loggedIn("admin", "admin"))  
store.dispatch(updateUserName("priyanka", "jain","prynka.m.jain@gmail.com"))  
store.dispatch(updateUserName("test", "test","test@gmail.com"))  
unsubscribe()   

The output will display as below,

As per the above code, we have defined 2 cases in reducer, Now we will see by creating multiple reducers as below,

const redux = require('redux')  
  
console.log("Index js in redux app")  
const LOGIN = 'LOGIN'  
const USER_DETAIL = 'USER_DETAIL'  
// action  
function loggedIn(user, pwd) {  
    return {  
        type: LOGIN,  
        username: user,  
        password: pwd,  
        loggedInStatus: ""  
    }  
}  
function updateUserName(FirstName, LastName, UserName) {  
    return {  
        type: USER_DETAIL,  
        FirstName: FirstName,  
        LastName: LastName,  
        UserName: UserName  
    }  
}  
  
function callLoginApi(username, password) {  
    if (username === 'admin' && password === 'admin') {  
        return "Login Success";  
    } else {  
        return 'Invalid email and password';  
    }  
}  
  
const initialLoginState = {  
    username: "test",  
    password: "test",  
    loggedInStatus: ""  
}  
  
const initialUserState = {  
    FirstName: "",  
    LastName: "",  
    UserName: ""  
}  
  
const loginReducer = (state = initialLoginState, action) => {  
    switch (action.type) {  
        case LOGIN:  
            return {  
                ...state,  
                username: action.username,  
                password: action.password,  
                loggedInStatus: callLoginApi(action.username, action.password)  
            }  
        default:  
            return state  
    }  
}  
  
const UserReducer = (state = initialUserState, action) => {  
    switch (action.type) {         
        case USER_DETAIL:  
            return {  
                ...state,  
                FirstName: action.FirstName,  
                LastName: action.LastName,  
                UserName: action.UserName  
            }  
        default:  
            return state  
    }  
}   

Now after updating code, we have 2 initial states and 2 reducer methods but there is a problem that store accepts only 1 reducer method so to solve that issue we have a function in the library named combineReducer(),

combineReducer()

The combineReducers helper function turns an object whose values are different reducing functions into a single reducing function you can pass to createStore.

The result of the reducer calls every child reducer, collect its result into a single state object. The state produced by combineReducer() namespace the state of each reducer under their keys are passed to combine Reducer().

Syntax:

combineReducer({key1: reducerName1,key2:reducerName2})

A state can be controlled by key names by using different keys for the reducers in the passed objects.

For example, for the above code, you can call,

const rootReducer = combineReducer({  
    login : loginReducer,  
    userDetail : UserReducer  
})  
const store = createStore(rootReducer) 

Now the final code goes as below,

const redux = require('redux')  
  
console.log("Index js in redux app")  
  
const createStore = redux.createStore  
const combineReducer = redux.combineReducers  
  
const LOGIN = 'LOGIN'  
const USER_DETAIL = 'USER_DETAIL'  
// action  
function loggedIn(user, pwd) {  
    return {  
        type: LOGIN,  
        username: user,  
        password: pwd,  
        loggedInStatus: ""  
    }  
}  
function updateUserName(FirstName, LastName, UserName) {  
    return {  
        type: USER_DETAIL,  
        FirstName: FirstName,  
        LastName: LastName,  
        UserName: UserName  
    }  
}  
  
function callLoginApi(username, password) {  
    if (username === 'admin' && password === 'admin') {  
        return "Login Success";  
    } else {  
        return 'Invalid email and password';  
    }  
}  
  
const initialLoginState = {  
    username: "test",  
    password: "test",  
    loggedInStatus: ""  
}  
  
const initialUserState = {  
    FirstName: "",  
    LastName: "",  
    UserName: ""  
}  
  
const loginReducer = (state = initialLoginState, action) => {  
    switch (action.type) {  
        case LOGIN:  
            return {  
                ...state,  
                username: action.username,  
                password: action.password,  
                loggedInStatus: callLoginApi(action.username, action.password)  
            }  
        default:  
            return state  
    }  
}  
  
const UserReducer = (state = initialUserState, action) => {  
    switch (action.type) {         
        case USER_DETAIL:  
            return {  
                ...state,  
                FirstName: action.FirstName,  
                LastName: action.LastName,  
                UserName: action.UserName  
            }  
        default:  
            return state  
    }  
}  
  
const rootReducer = combineReducer({  
    login : loginReducer,  
    userDetail : UserReducer  
})  
const store = createStore(rootReducer)  
console.log("Initial State", store.getState())  
const unsubscribe = store.subscribe(() => console.log('Updated state', store.getState()))  
store.dispatch(loggedIn("user", "user"))  
store.dispatch(loggedIn("admin", "admin"))  
store.dispatch(updateUserName("priyanka", "jain", "prynka.m.jain@gmail.com"))  
store.dispatch(updateUserName("test", "test", "test@gmail.com"))  
unsubscribe()  

It will display output as,

So this way we can implement multiple reducers in Redux. It may be used to maintain AuthReducer, ProfileReducer and so on.

Important points while using combineReducer()

There are some basic rules that must be followed while using combineReducer() Like,

  1. For any action in the reducer, it must return a state given as a first argument.
  2. It should never return undefined so while writing code should have proper return statement and error should be managed properly else combineReducer will throw it instead of letting the error manifest itself somewhere else.

Summary

In this article, we have learned about multiple reducer concept and how it can be implemented using combineReducer() method in Redux.

Now in the next article we will be learning about Middleware in Redux along with Async actions.

Any question or feedback or suggestion, please do comment and let me know.

One comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s