Whenever there is a requirement for state management, the first name that pops in the head is REDUX. With approximately 18M downloads per month, it has been the most apparent and unmatched state management tool.
But the new React Context API is giving the redux a healthy competition and trying to replace it.
I will first give a brief explanation for both, and then we can deep dive into the details.
What is Redux?
Redux is most commonly used to manage state or data of a React app. It is not just limited to React apps; it can be used with Angular and other frameworks as well. But when using react, the most common and obvious choice is to use redux.
Redux provides a centralized store(state) that can connect with various react containers/components.
This state is not mutable and accessible directly, to change the state data we need to dispatch the actions and then the reducers will update the data in the centralized state.
What is React’s Context API?
Context API provides a way to solve a simple problem which you will face in almost all react apps, how can we manage a state or pass data to not connected components.
Let’s first see an example of a sample application with redux used for state management.
The state is always changed by dispatching an action.
https://gist.github.com/hch2904/c1e90dd49c8143ea562dc05676b502c7#file-rvr_actions_example_1-jsx
Then a reducer is present to update the global state of the app. Below is a sample reducer.
https://gist.github.com/hch2904/c1e90dd49c8143ea562dc05676b502c7#file-rvr_reducer_example_2-jsx
Below would be a sample app.js file.
https://gist.github.com/hch2904/c1e90dd49c8143ea562dc05676b502c7#file-rvr_app_example_3-jsx
The last step would be to connect the react component to the reducer, which would subscribe to the global state and automatically update the data, passed as props.
https://gist.github.com/hch2904/c1e90dd49c8143ea562dc05676b502c7#file-rvr_todo_component_4-jsx
This is a fundamental and trivial implementation of the react-redux setup. But there is a lot of boilerplate code that needs to be taken care of.
Now, let’s see how does React’s context API work. We will update the same code and use the context API and remove redux.
Context API consists of three things:
- Context Object
- Context Provider
- Context Consumer
First of all, we will create a context object.
https://gist.github.com/hch2904/c1e90dd49c8143ea562dc05676b502c7#file-rvr_create_context_5-js
We can create contexts in various forms. Either in a separate file or in the component itself. We can create multiple contexts, as well. But what is this context?
Well, a context is just a JSON that holds some data(It can hold functions as well).
Now let’s provide this newly created context to our app. Ideally, the component that wraps all the child components should be provided with the context. In our case, we are providing context to our app itself. The value prop in the <TodoContext.Provider> set here passes down to all the child components.
https://gist.github.com/hch2904/c1e90dd49c8143ea562dc05676b502c7#file-rvr_provider_example_6-jsx
Here is how we can consume our provided context in the child components.
https://gist.github.com/hch2904/c1e90dd49c8143ea562dc05676b502c7#file-rvr_consumer_example_7-jsx
The special component <TodoContext.Consumer> is injected into the context provided. The context is the same object that is passed to the value prop of <TodoContext.Provider>. So if the value changes over there, the context object in the consumer is also updated.
But how do we update the values? Do we need actions?
So here we can use the standard React State management to help us. We can create the state in our App.js file itself and pass the state object to the Provider. The example given below would provide you with a little more context. 🙂
In the above code, we are just updating the state normally as we would in a normal class-based React component. Also, we are passing methods as references to the value prop, so any component that is consuming the context will have access to this function and can easily update the global state.
So that is how we can achieve global state management using the React Context API instead of using redux.
So should you get rid of redux completely?
Let’s look into a little comparison listed down below:
Redux | React Context API | |
Learning Curve | Redux is a whole new package that needs to be integrated into an app, it takes some time to learn the basic concepts and standard code practices that we need to follow in order to have the react and redux working together smoothly. If you know react then it certainly helps to speed things up to learn and implement redux. | React context, on the other hand, works on the state principle which is already a part of React, we only need to understand the additions to the API and how we can use the providers and consumers. In my opinion, a react developer can get familiarized with the concept in a short while |
Refactoring Effort | To refactor the code to redux API would depend on the project itself, a small scale app can be easily be converted in 3 to 4 days but if there is a big app that needs to converted it can take some time. | |
Code Size | When using redux the code size of the web app is increased quite a bit as we include quite some packages just to bind all the stuff together. redux – 7.3kB react-redux – 14.4kB |
On the other hand, the context API is baked in the react package. So no additional dependencies are required |
Scale | Redux is known for it’s scaling capabilities, in fact, while building a large scale app redux is the first choice, it provides modularity (separating out reducers, actions) and a proper flow which can be easily scalable. | The same cannot be said for the react context API, as everything is managed by the state property of React, while we can create a global higher-order component that can contain the whole app state, but this is not really maintainable and not easy to read code. |
In my opinion, a small scale app can easily adapt to the react context API. To integrate redux, we need three to four separate packages. This adds to the final build, bigger bundle size, a lot more code to process, which would increase the render times.
On the other hand, React context API is built-in, and no further package is required to use it.
However, when we talk about large scale apps, where there are numerous components and containers involved, I believe the preferred way to go is redux, as redux provides maintainability, ability to debug your code. Their various middlewares present helps to write efficient code, handle async code and debug better. We can separate the actions dispatchers and reducers in redux, which provide us with an easier and defined coding pattern.
The last approach can be to use both of these, but I have not tried it. We can connect containers with redux, and if the containers have deep child component trees, we can pass the data to children using context objects.