Introduction

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

Multiple Reducers

Redux has the pattern of a single store principle to maintain one immutable store; however, it also has the concept of multiple reducers.
The multiple reducers concept is to handle single functionality per reducer.
For example, we can have 2 reducers. One is to manage the user login and other is to update the user details
So, I am updating my index.js code as below.
  1. const redux = require('redux')
  2. console.log("Index js in redux app")
  3. const LOGIN = 'LOGIN'
  4. const USER_DETAIL = 'USER_DETAIL'
  5. // action
  6. function loggedIn(user, pwd) {
  7. return {
  8. type: LOGIN,
  9. username: user,
  10. password: pwd,
  11. loggedInStatus: ""
  12. }
  13. }
  14. function updateUserName(FirstName,LastName,UserName){
  15. return{
  16. type:USER_DETAIL,
  17. FirstName : FirstName,
  18. LastName:LastName,
  19. UserName:UserName
  20. }
  21. }
  22. function callLoginApi(username, password) {
  23. if (username === 'admin' && password === 'admin') {
  24. return "Login Success";
  25. } else {
  26. return 'Invalid email and password';
  27. }
  28. }
  29. const initialState = {
  30. username: "test",
  31. password: "test",
  32. loggedInStatus: "",
  33. FirstName : "",
  34. LastName : "",
  35. UserName :""
  36. }
  37. const reducer = (state = initialState, action) => {
  38. switch (action.type) {
  39. case LOGIN:
  40. return {
  41. ...state,
  42. username: action.username,
  43. password: action.password,
  44. loggedInStatus: callLoginApi(action.username, action.password)
  45. }
  46. case USER_DETAIL:
  47. return {
  48. ...state,
  49. FirstName: action.FirstName,
  50. LastName: action.LastName,
  51. UserName: action.UserName
  52. }
  53. default:
  54. return state
  55. }
  56. }
  57. const store = redux.createStore(reducer)
  58. console.log("Initial State", store.getState())
  59. const unsubscribe = store.subscribe(() => console.log('Updated state', store.getState()))
  60. store.dispatch(loggedIn("user", "user"))
  61. store.dispatch(loggedIn("testing", "testing"))
  62. store.dispatch(loggedIn("admin", "admin"))
  63. store.dispatch(updateUserName("priyanka", "jain","[email protected]"))
  64. store.dispatch(updateUserName("test", "test","[email protected]"))
  65. unsubscribe()
The output will display as below.
As per the above code, we have defined 2 cases in the reducer. Now, we will see it by creating multiple reducers as below,
  1. const redux = require('redux')
  2. console.log("Index js in redux app")
  3. const LOGIN = 'LOGIN'
  4. const USER_DETAIL = 'USER_DETAIL'
  5. // action
  6. function loggedIn(user, pwd) {
  7. return {
  8. type: LOGIN,
  9. username: user,
  10. password: pwd,
  11. loggedInStatus: ""
  12. }
  13. }
  14. function updateUserName(FirstName, LastName, UserName) {
  15. return {
  16. type: USER_DETAIL,
  17. FirstName: FirstName,
  18. LastName: LastName,
  19. UserName: UserName
  20. }
  21. }
  22. function callLoginApi(username, password) {
  23. if (username === 'admin' && password === 'admin') {
  24. return "Login Success";
  25. } else {
  26. return 'Invalid email and password';
  27. }
  28. }
  29. const initialLoginState = {
  30. username: "test",
  31. password: "test",
  32. loggedInStatus: ""
  33. }
  34. const initialUserState = {
  35. FirstName: "",
  36. LastName: "",
  37. UserName: ""
  38. }
  39. const loginReducer = (state = initialLoginState, action) => {
  40. switch (action.type) {
  41. case LOGIN:
  42. return {
  43. ...state,
  44. username: action.username,
  45. password: action.password,
  46. loggedInStatus: callLoginApi(action.username, action.password)
  47. }
  48. default:
  49. return state
  50. }
  51. }
  52. const UserReducer = (state = initialUserState, action) => {
  53. switch (action.type) {
  54. case USER_DETAIL:
  55. return {
  56. ...state,
  57. FirstName: action.FirstName,
  58. LastName: action.LastName,
  59. UserName: action.UserName
  60. }
  61. default:
  62. return state
  63. }
  64. }
Now after updating the 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 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 and collects 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 the following
  1. const rootReducer = combineReducer({
  2. login : loginReducer,
  3. userDetail : UserReducer
  4. })
  5. const store = createStore(rootReducer)
Now, the final code goes as below.
  1. const redux = require('redux')
  2. console.log("Index js in redux app")
  3. const createStore = redux.createStore
  4. const combineReducer = redux.combineReducers
  5. const LOGIN = 'LOGIN'
  6. const USER_DETAIL = 'USER_DETAIL'
  7. // action
  8. function loggedIn(user, pwd) {
  9. return {
  10. type: LOGIN,
  11. username: user,
  12. password: pwd,
  13. loggedInStatus: ""
  14. }
  15. }
  16. function updateUserName(FirstName, LastName, UserName) {
  17. return {
  18. type: USER_DETAIL,
  19. FirstName: FirstName,
  20. LastName: LastName,
  21. UserName: UserName
  22. }
  23. }
  24. function callLoginApi(username, password) {
  25. if (username === 'admin' && password === 'admin') {
  26. return "Login Success";
  27. } else {
  28. return 'Invalid email and password';
  29. }
  30. }
  31. const initialLoginState = {
  32. username: "test",
  33. password: "test",
  34. loggedInStatus: ""
  35. }
  36. const initialUserState = {
  37. FirstName: "",
  38. LastName: "",
  39. UserName: ""
  40. }
  41. const loginReducer = (state = initialLoginState, action) => {
  42. switch (action.type) {
  43. case LOGIN:
  44. return {
  45. ...state,
  46. username: action.username,
  47. password: action.password,
  48. loggedInStatus: callLoginApi(action.username, action.password)
  49. }
  50. default:
  51. return state
  52. }
  53. }
  54. const UserReducer = (state = initialUserState, action) => {
  55. switch (action.type) {
  56. case USER_DETAIL:
  57. return {
  58. ...state,
  59. FirstName: action.FirstName,
  60. LastName: action.LastName,
  61. UserName: action.UserName
  62. }
  63. default:
  64. return state
  65. }
  66. }
  67. const rootReducer = combineReducer({
  68. login : loginReducer,
  69. userDetail : UserReducer
  70. })
  71. const store = createStore(rootReducer)
  72. console.log("Initial State", store.getState())
  73. const unsubscribe = store.subscribe(() => console.log('Updated state', store.getState()))
  74. store.dispatch(loggedIn("user", "user"))
  75. store.dispatch(loggedIn("admin", "admin"))
  76. store.dispatch(updateUserName("priyanka", "jain", "[email protected]"))
  77. store.dispatch(updateUserName("test", "test", "[email protected]"))
  78. unsubscribe()
It will display the output as below.
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 the multiple reducers concept and how it can be implemented using the combineReducer() method in Redux. You can download the source code attached along with this article. Now in the next article we will be learning about Middleware in Redux along with Async actions.