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.
Top comments (0)