Is Context Better than Redux?

Patricia Arnedo
JavaScript in Plain English
5 min readApr 9, 2021

--

A picture in which a man, labeled “developer” checks out another woman labeled “context” while with his girlfriend labeled “redux”
The state of developer interest in context

If you’re learning to use Redux, you’ll probably agree that it can be overwhelming to keep up with all of its files, functions, types, actions, and reducers. Once you push through the initial confusion, you may find that using it becomes second nature — it’s highly structured, makes it easy to tell where bugs are coming from, and there’s a repeatable pattern when building features. But what if instead of tackling the Redux learning curve you just use the React createContext API? Compared to Redux, context provides a simpler way to manage data across components, and you may find yourself wondering why you bothered to learn Redux at all. This article explores whether Redux, despite being bloated (sorry old friend) and complicated to learn, still has a place in a developer’s toolbox.

What is Redux?

Let’s start by defining Redux. If you want to get really in-depth, you can check out the docs here. In a nutshell, Redux provides an organized and stable way to manage state across components in javascript applications by providing a single source of truth for your application’s state. It’s made up of these basic components:

  • Action: A javascript object with a type key that describes an application event that intends to change state.
  • Dispatch: A function that accepts an action and dispatches it to the store.
  • Store: An object that contains the state of your entire application.
  • Reducer: A function that accepts the previous state and an action from dispatch, updates the state object if necessary, and returns the updated state object.
  • Subscriptions: Allows components to subscribe to relevant parts of state in the store, preventing needless re-renders when changes are made to unrelated parts of state.

Data flows from a triggered action in the following steps:

  1. An application event such as a UI interaction or network callback creates an action. The type key in the action object describes this action.
  2. This action is sent to the dispatch function, which sends it to the store along with the previous state.
  3. In the store, the reducer takes an action and the previous state, calculates the new state, and returns the updated state.
  4. Subscribed components will receive the updated state and update the UI or perform other actions accordingly.

Here is a helpful gif from the Redux docs to help paint a picture of how state gets updated using Redux.

The actual implementation of Redux has more components, such as thunk middleware that wraps the base dispatch function to better deal with asynchronous side effects, but I’ll keep it simple to compare the core functionality and data flow.

What is context?

Now let’s define React’s createContext API. You can find the context docs here. Similar to Redux, context is used to share information across components at different levels in your component tree without prop drilling. Unlike Redux, context is not exclusively a state management system, it can also be used for theming and routing. State management is one of its use cases, but not its sole purpose. Context is a part of React, so you will not need to install a third-party library or deal with boilerplate as is the case with Redux. Context utilizes three basic elements:

  • Context Provider: Provides the shared data to the pertinent components. It is usually declared in the root component so the entire application has access to it, or in a component that nests around all components that will need access to it.
  • Context Object: The data that is provided by the Context provider. Changes to this data will be reflected in all components that consume the data.
  • Context Consumer: Components that subscribe to state provided by Context.

The steps you need to take to use context are as follows:

  1. Create a context to be shared with components.
  2. Provide the context to the components by wrapping it with a context provider.
  3. Use the context in components that require it.

Comparing the two

At first glance, using context seems like a pretty sweet deal, and in many cases it is! It’s built into React, it’s easy to learn and use, and it feels lightweight compared to Redux because it’s more streamlined. It’s important to note that context is not only a state management system. It is used to provide data between components that may be deeply nested, but this data is not always state, so the standard context usage does not provide robust state management. In order to leverage context as a state management system you have to make use of React’s dispatch and reducers, which work similarly to Redux’s. Context has the advantage when it comes to providing a native solution for state management and preventing prop drilling with less bloat.

If you are working in an enterprise setting with a large codebase and multiple engineers, Redux may look more appealing. It forces you to be organized and follow certain patterns. Even if you didn’t write the code you can follow the trusty Redux trail, from action, to dispatch, to reducer, and find what’s going wrong because of Redux’s code structure.

Redux may have an edge over context when it comes to debugging, not only because of predictable code structure, but because of tools like Redux Devtools and other plugins that provide powerful insights into how state changes over time. Redux also allows the use of middleware, which incorporates third-party extensions into your Redux flow to provide more customized solutions. Because Redux is a library, it is more powerful and full of features that context simply doesn’t have.

The last reason why Redux is still viable is that context is not recommended for use in applications that frequently update. Redux is efficient when it comes to eliminating unnecessary re-renders, but out of the box, context can become inefficient. This is because all components that are context consumers will update when any value in a context object updates, regardless of whether the change was relevant to that component. There are workarounds to this, such as using memoization to remember previous values to prevent re-renders, but context alone doesn’t deal with the issue.

It’s important to note that neither context nor Redux are intrinsically “better”, but there is likely one that is “better” for your specific use case. As long as you understand your project and its needs, it will become clear which is best for the job.

More content at plainenglish.io

--

--