How to use hooks (useContext, useReducer) to replace redux
In the beginning of development with React, Redux has been a great tool for managing data with certain drawbacks. The drawbacks include:
- Sometimes we have too many layers of components if they are connected. The ‘connect’ is actually a Higher Order Component.
- Sometimes we need to pass data through multiple levels to reach the component needed
React has introduced context and its own hook useContext to prevent from passing data through layers. With the hook useReducer, we can easily create a dispatch function by yourself. With the help of context, we can use the dispatch function everywhere, then why not make a try with replacing redux with useContext and useReducer ?
In this article, I will write down a tutorial on how to replace redux by useContext and useReducer with a working example. The code is here.
Some thinking on ‘use’ and ‘with’ in React
Just before this tutorial, I want to share something with hooks. React Hooks reinforce the development of react and make it more flexible. In general, there are two ways : ‘use’ and ‘with’. ‘use’ is always used for customizing hooks, for example, ‘useEffect’, or customized ‘useMyEffect’, ‘useContext’, or ‘useMyContext’. ‘with’ is always used as HOC component. You can check an example of it with my article Create HOC pattern ‘withContext’ for context.
Ok, let’s start our tutorial:
Step 1: Create context
The first step is to create Context. In react-redux, we distinguish state and dispatch with ‘mapStateToProps’ and ‘mapDispatchToProps’, so in our example, we also create two context to distinguish ‘data’ and ‘action’.
Let’s create two contexts: StateContext and DispatchContext with `React.createContext`.
Step 2: Prepare the reducer function
I am making a simple example, and this reducer function supports two actionTypes: ADD and SUBTRACT.
Step 3: Create Context provider for state and dispatch
Then, in the ContextProvider component, we wrap our children component inside the two context providers, to make data and actions available anywhere.
We also need to use useReducer with the reducer function to have state and dispatch, and then pass them as the initial values in `<StateContext.Provider/>` and `<DispatchContext.Provider/>`
Step 4: Create customized hooks for useState and useDispatch
In order to use the state and dispatch actions everywhere in the app, we customize two hook functions.
In the hook useUIDispatch, we get the dispatch function from context, return a series of actions with ActionTypes. We use useCallback and useMemo for memoization.
Step 5: Wrap the <App/> inside the Provider
Step 6: Use customized hooks to get value and dispatch actions
That’s all of it. You can find a working demo on here. Thanks for reading !