Redux enhancer
Andrés Valdivia Cuzcano
Posted on June 28, 2023
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
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
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);
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:
- The enhancer must return a new Store Creator
- You can add any new functionalities to the Store Creator or the Store, as we will see later
- The new Store Creator must return a new Store
- 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);
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);
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.
Posted on June 28, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.