What is decorating a store?
A store is an immutable object in redux that holds the state of your application. It brings together actions, reducers, and states to make up an application. To create a store, import the createStore API from the redux core library, as shown below:
import { createStore } from 'redux'
Note: You can only create a single
storein an application.
Decorators
Decorators are a piece of code that wraps another piece of code to decorate it. Decorators enhance a function without modifying it.
There are two types of functions that can be used as decorators:
Higher-order function
A higher-order function is a function that returns a function, takes a function as input parameter, or both. Consider the example of a higher-order, shown below:
function greetUser(name){console.log("Hello ",name);}function decoratorFunc(fn){return function(args) {console.log("This is higher-order function example");fn(args);}}console.log("Calling simple greetUser()");greetUser("Ali");var decoratedFunction = decoratorFunc(greetUser);console.log("Calling wrapped greetUser()");decoratedFunction("Ali");
Explanation
greetUser()is a function that greets the user by printing the user’s name.decoratorFunc()is the higher-order function that decorates the functiongreetUser()by adding an output string.decoratedFunction()is the final decorated function, which isgreetUser()wrapped with withdecoratorFunc().
Compose function
Compose function is used to combine multiple functions together to build more complex functions. To build a complex function, import the complex() function from the redux library, as shown below:
import { compose } from 'redux'
Why do we need the compose function?
Let’s suppose we want to apply four decorators, decorator1(), decorator2(), decorator3(), and decorator4(), to a function func1. We can use the same approach as explained in the example of higher-order functions shown above. The code will be as follows:
var decoratedFunction = wrapper4( wrapper3( wrapper2( wrapper1( func1() ) ) ) );
The output of func1() will be passed to wrapper1(). The output of wrapper1() will be passed to wrapper2(), and so on. As the number of wrappers increase, the code becomes more and more complex. The compose() function can be used to implement the same functionality, as explained above. The code will be as follows:
var decoratedFunction = compose(wrapper4, wrapper3, wrapper2, wrapper1)(func1);
Decorating a store
A store can be decorated by using:
- Store enhancers
- The
applyMiddlewarefunction
Store enhancers
Store enhancers are higher-order functions that are used to enhance the functionality of a store. Store enhancers have access to all internal methods of a store.
Example
Consider the code snippet below, which shows the example of a store enhancer, persistStore():
const persistStore = (next) =>(reducer, initialState, enhancer) => {let store;if(typeof initialState !=='function') {store = next(reducer, initialState, enhancer);}else{const preloadedState = initialState || JSON.parse(localStorage.getItem('@@PersistedState') || {})store = next(reducer, initialState, enhancer);}store.subscribe( () => localStorege.setItem('@@PersistedState', JSON.stringify(store.getState())) );return store;}
Explanation
-
lines 3-7: If
initialStateis passed as a parameter, create the store with it. -
lines 8-7: If
initialStateis not passed as a parameter, read the initial state fromlocalStorageand create the store with it. -
line 13: To keep your
localStoragein sync with the state, subscribe to state updates and save the state tolocalStorage.
applyMiddleware function
applyMiddleware is a store enhancer provided by redux to add to the functionality of the redux middle-ware.
Note:
applyMiddlewareis the only store enhancer provided byredux.
Example
Consider the code snippet below, which shows an example of the applyMiddleware function:
import { createStore, applyMiddleware } from 'redux'import todos from './reducers'function logger({ getState }) {return next => action => {console.log("current action", action);const nextAction = next(action);console.log('dispatched state', getState());return nextAction;}}const store = createStore(todos , initialState=[ ] , applyMiddleware(logger));store.dispatch({ type: 'ADD_TODO', text: 'applyMiddleware function'})
Explanation
A custom middleware function logger() is defined in lines 4-11. The logger() function logs the action and the state when the action is dispatched. The applyMiddleware function is used in line 13 to apply the custom middleware function logger() to the store.
Free Resources