Working with Multiple Reducers in Redux

Working with Multiple Reducers in Redux

Part - II (Combine Reducers and Middleware)

·

3 min read

Recap

In the last article, we saw how to get started with Redux using simple Javascript code and saw some of the terms related to Redux like Action, Action Creators, Reducers, and Store. Now, we will move forward with other essential concepts while learning Redux that come in handy when working on React Applications that use Redux for State Management.


Multiple Reducers

While using a single reducer function in our application, the reducer logic becomes too complex with time and hard to scale when doing new changes. So, it is a best practice to create multiple reducers that separate concerns between them and only take care of the states associated with them.

e.g., Say we have a shop that sells cakes and ice-creams, so if the store size is small, it will be easy to maintain the shop with a single shopkeeper who can manage both cake and ice-cream counters. But, if the store size increases then it will become tough to manage the entire state of the store by a single shopkeeper, so we can then keep two shopkeepers - one that manages all the stuff related to cakes and the other that manages ice-cream stuff.

Using multiple reducers has the below advantages -

  • It makes code easy to debug due to separate concerns b/w reducer logic
  • Code becomes scalable and easy to maintain

combineReducers

Redux provides us with a function called combineReducers that accepts an object with key as reducer-alias (used to fetch data from store) and value as an associated reducer.

const RootReducer = combineReducers({
      cake:cakeReducer,
      iceCream:iceCreamReducer
});

Now, the store will have one global state and that state will have two properties in it - cake and iceCream with their respective data.

const previousInitialState = {noOfCakes :10 , noOfIceCreams:20};

// state after using multiple reducers

const newInitialState = { cakes : {noOfCakes:10} ,
     iceCream : {noOfIceCreams:20} };

Now, you can easily pass this rootReducer to the redux store as -

const store = createStore(rootReducer);

One thing to remember here is, that when the action is dispatched, all the reducer functions receive that action but only one acts on it while other reducer function ignores it.


Middleware

  • Middleware helps in extending redux with custom functionalities like logging state changes in redux store, crash reporting, and performing asynchronous tasks in redux.

  • Redux provides applyMiddleware to apply middleware in Redux applications.

  • It provides a 3rd-party extension point between dispatching an action and the moment it reaches the reducer.

  • We are going to look at redux-thunk , the most widely used middleware to perform the asynchronous tasks in the article.

To use redux-thunk in our application, first we pass it to store as below -

import thunk from "redux-thunk";
import { createStore, applyMiddleware } from 'redux'

const store = createStore(rootReducer , applyMiddleware(thunk));

Async Action Creators

  • It is just like a normal action creator that we already saw in the previous article, but instead of returning the action object, it returns a function that can do async operations.

  • It receives the dispatch method as an argument to dispatch any actions.

const fetchUsers = () => {
    return (dispatch) => {
        dispatch({type:'fetching'});
        const data = await axios.get('api endpoint');
        dispatch({type:'success' , payload:data.users});
  }
}

Now to dispatch this above-created action creator, we dispatch it as -

const store = createStore(rootReducer,applyMiddleware(thunk));

  store.dispatch(fetchUsers())

Conclusion

Hope you might have understood the basic concepts of Redux by reading this article and are ready to use Redux in your next project.

If you liked this article, please be sure to ❤ it. Thanks in Advance😊.