Redux enhancer
Tags: javascript, webdev, redux, development
Published: 2023-06-28 13:30:29

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.

```tsx

type StoreCreator = (reducer: Reducer, initialState?: State, enhancer?:Enhancer) => Store
```

![Store creator without enhancer](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/as1dgcj0ts8m5d7z3c1x.png)

## 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:

```tsx
type StoreEnhancer = (currentStoreCreator: StoreCreator) => StoreCreator
```

![Store creator using an enhancer](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cfrs0a2szg2qu41xeyyv.png)

Let's create a dummy enhancer.

```jsx
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:
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:
    
```jsx
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](https://redux.js.org/usage/configuring-your-store#enhancersmonitorreducerjs)):
    
```jsx
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.