How to do a Redux store with React hooks
Redux is one of the most used global state management for JavaScript, it can be used with frameworks or vanilla JS, and it allows the application to have a global store (state) that all the components can access and modify using functions to preserve its integrity. Redux is better put to use in very large applications using a component-based framework like React, whereas the application grows the concept of lifting the state brings more complexities. For this case, the “shared global state” is a more suitable method because any component of the application can access the store without having anything to be passed down to it.
Redux has an interesting way to manage the store that prevents unintended changes and controls access to it. This is achieved by using 3 core elements:
• Store: Is the state that the whole application can access, it can be anything from a big JSON object to an array or a single variable.
• Reducers: Reducers handle how the state is changed depending on the action. There can be many reducers but to register them to Redux they have to be combined into one. This segmentation allows for a reducer to handle a specific part of the store without making changes to the other parts. The reducer works based on actions and payloads for those actions, and each one interacts differently with the store. To activate or call the reducer an action have to be dispatched using the dispatch function.
• Actions: These objects are the ones that tell the reducer what has to be done to the store. Generally, they come associated with a payload that contains the information that has to be introduced or changed in the state, but the payload is not required, this is how the control over the store is handled because each action modifies only the part that it is intended to.
There are many other aspects to the Redux store management but these 3 are the core elements that make it work.
Thanks to the infinite functionality of React hooks, the same concept of Redux can be achieved with the useContext and useReducer hooks. The context helps in the sharing of the state to all the components wrapped by it, creating an equivalent to the store, and the use reducer controls the changes over it.
Let’s start learning how to do it. First, you have to create a context for the store to live in.
This creates the context for the application and initializes the store as an empty object. Depending on where you created the context, for example in your index.js or your App.js, the following steps might change, my recommendation is to create a separate component that handles all the context stuff in one place and makes your code cleaner. With this said the next thing is to create a component to handle the context.
and then wrap your app in it.
Ideally, this will wrap your whole application but you can create a different context for different sections, again this depends on the functionality that you want to have and the isolation between sections, for this example there is only one context and it is applied to the whole application.
So far we have granted access to an empty object to the whole application but we can’t access that value from any component. For this, we are going to create our own custom hook that we are going to use anytime we need to access the values of the store. This hook will be defined in the same file as the context handling component for simplicity and will use the useContext React hook.
Now we can access the values of the store from anywhere, but the store doesn’t have any values in it, is just an empty object. Here is where the useReducer React hook comes in, this hook returns the state and the dispatch function and receives the full reducer function and the initial state. With this, our context component is getting beefier.
The value in the context provider is the state that will be accessible by the application. Now we have reached a point where decisions have to be made because to use the dispatch function you have two options: send it as part of the state object or my personal preference, create wrapper functions that change one part of the state like an individual reducer and have the dispatch called from those, these wrapper functions will have to be passed in the value for the context. With this said the full component for the context will be like this.
There are some functions there that the only thing they do is to return the corresponding action and payload ready to use by the dispatch. Here is a couple of those for you to get an idea of how they work, these are stored in a separate file called actions.js to organize the code.
Now the only thing missing is the reducer for the store. This is an example of how to do it, this reducer lives in a file called reducer.js.
And that is it, with these components, you will have a functional store just like the Redux one works. To use all this functionality that we just created you have to use the custom hook inside one of your components.
This final example shows how everything ties together using the custom hook that we created to access the store. In this example, the app component is getting some data when it’s mounted and storing it in the context store that we created.
Either way you choose to manage your state is always good to know new and different ways to achieve the same result, and hopefully, this article gave you that knowledge and perspective. Check out my other articles, there is one about React hooks if you are interested in learning more about those, and if you like this one give it a clap. Thank you for reading and I hope it helped you in your React journey.