DEV Community

Cover image for Redux enhancer
Andrés Valdivia Cuzcano
Andrés Valdivia Cuzcano

Posted on • Updated on

Redux enhancer

In this blog we will talk about how an enhancer works and how it allows us to “create” a new Store Creator and "replace" the createStore function provided by Redux.

Store creator

As we know, we create a Store using the createStore function. This function takes a reducer as its first argument, and an initial state (optional) and an enhancer (also optional) as its second and third arguments, respectively. The createStore function returns a Store.


type StoreCreator = (reducer: Reducer, initialState?: State, enhancer?:Enhancer) => Store
Enter fullscreen mode Exit fullscreen mode

Store creator without enhancer

What is an enhancer?

An enhancer is simply a higher-order function, this means that it can take functions as arguments or return a function. In this case, an enhancer takes the current StoreCreator as its argument and returns a new StoreCreator. We can represent it as follows:

type StoreEnhancer = (currentStoreCreator: StoreCreator) => StoreCreator
Enter fullscreen mode Exit fullscreen mode

Store creator using an enhancer

Let's create a dummy enhancer.

import { createStore } from "redux";

// the enhancer takes a CreateStore as argument
const dummyEnchancer = (createStore) => {
    return (reducer, state, enhancer) => {
        const store = createStore(reducer, state, enhancer)

        // and return a new Store
        return { ...store }
    }
}

const store = createStore(rootReducer, undefined, dummyEnchancer);
Enter fullscreen mode Exit fullscreen mode

In the example above, we can see that we can customize the StoreCreator function as we wish. The only rule is that we must return a new StoreCreator function, which will replace the one provided by Redux.

In summary:

  1. The enhancer must return a new Store Creator
  2. You can add any new functionalities to the Store Creator or the Store, as we will see later
  3. The new Store Creator must return a new Store
  4. Add the enhancer as the last parameter to the createStore function

Examples:

1. Customize the store dispatch:

import { createStore } from "redux";

const greetEnhancer = (createStore) => {
    return (reducer, state, enhancer) => {
        // create a store
        const store = createStore(reducer, state, enhancer)

        // create a "Dispatch enhancer"
        const newDispatch = (action) => {
            const result = store.dispatch(action)
            // add some logic after dispatch any action
            console.log('Do something here :D')
            return result
        }

        return {
            ...store
            dispatch: newDispatch
        }
    }
}

const store = createStore(rootReducer, undefined, greetEnhancer);
Enter fullscreen mode Exit fullscreen mode

In this example, we create a store and use its dispatcher inside a new one. This ensures that the action is dispatched and that we can add our own logic. Finally, we return the new StoreCreator, which provides a new store with the dispatcher we just created.

2. Customize the store reducer (source):

import { createStore } from "redux";

const monitorReducerEnhancer =
  createStore => (reducer, initialState, enhancer) => {

        // create an "Reducer enhancer"
    const monitoredReducer = (state, action) => {
            // add time measurement when using the store reducer
      const start = performance.now()
      const newState = reducer(state, action)
      const end = performance.now()
      const diff = round(end - start)

      console.log('reducer process time:', diff)

      return newState
    }

        // return the new Store created using the new reducer
    return createStore(monitoredReducer, initialState, enhancer)
  }

const store = createStore(rootReducer, undefined, monitorReducerEnhancer);
Enter fullscreen mode Exit fullscreen mode

In the above example, we create an enhancer that contains a "new reducer" which wraps the original reducer. This allows new logic to be executed each time the reducer is used. Finally, we return the new StoreCreator that creates a store which uses the monitoredReducer as the reducer.

Top comments (0)