DEV Community

Cover image for React Context: The Ultimate Handbook
Rushit Jivani
Rushit Jivani

Posted on

React Context: The Ultimate Handbook

Years ago, the Context API was introduced as an experimental feature with a warning “in the future this API can break”. As the Context API was experimental, most React developers were not confident enough to use it.

But after the release of React v16.3, we get the new Context API, which brings enhanced efficiency and is fully prepared for production. and now it’s one of the Important React Concepts.

In this comprehensive guide, we will explore the concept of React context, its implementation, and guidelines for its proper usage in various scenarios. Additionally, we will discuss the dos and don’ts of utilizing context effectively to maximize its benefits.

Let’s get started!

What is React context?

React context is a way to easily share and access data across different components in our React application, without the need for prop drilling.

Think of context as a global object accessible within a specific subtree of React components.

Why this Context API is so important?
In React, components are organized in a hierarchical structure resembling a tree. The topmost component is the root node, and all other components are connected to it. Data in this structure flows in a single direction, from the top down.

For instance, let’s consider this app where both ShopDisplay and Cart need access to the items a user has put into their shopping cart. We can pass props down into the Shop Display component and Cart component so that they have access to cartItems and setCartItems.

export default function App() {
  const [cartItems, setCartItems] = useState([]);

  return (
    <div className="App">
      <ShopDisplay handleCartItems={setCartItems} />
      <Cart cartItems={cartItems} />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Here as you can see what is happening above:

  1. App — Has access to both cartltems and setCartltems
  2. ShopDisplay — Has access to setCartltems via props
  3. Cart — Has access to cartltems via props

Prop drilling can be somewhat like a Russian nesting doll with several layers of props going further and further into child components.

Image description

Here the Cart component can also pass down cartItems to any child components it has.

In React, data only flows in one direction. So, if you need data at a deep level in your component tree, you have to pass it down as a prop through all the child components. This can be a lot of work, so people use state management libraries like Redux or MobX to make it easier. If you’ve used either of these libraries, you’ve already used the Context API indirectly. That’s because Redux uses the Context API internally.

This is a picture that shows how context can be used to share data with all the components in a React app.

Image description

When should you use React context?

  • You want to share data with many components at different nesting levels. Like Theming (like dark or light mode), User data (the currently authenticated user), Multilingual Support (like user language or locale), and application configuration (like base URL).
  • When the same prop (data) is passed through several components.

Image description

How do I use React context?

Using the context in React requires 3 simple steps: creating the context, providing the context, and consuming the context.

A. Creating the context

The built-in factory function createContext(default) creates a context instance:

// context.js
import { createContext } from 'react';

export const Context = createContext('Default Value');
Enter fullscreen mode Exit fullscreen mode

The factory function accepts one optional argument: the default value.

B. Providing the context

Context.Provider component available on the context instance is used to provide the context to its child components, no matter how deep they are.

To set the value of context use the value prop available on the <Context.Provider value={value} />:

import { Context } from './context';

function Main() {
  const value = 'My Context Value';
  return (
    <Context.Provider value={value}>
      <MyComponent />
    </Context.Provider>
  );
}
Enter fullscreen mode Exit fullscreen mode

Again, what’s important here is that all the components that’d like later to consume the context have to be wrapped inside the provider component.

If you want to change the context value, simply update the value prop.

C. Consuming the context

Consuming the context can be performed by the useContext(Context) React hook:

import { useContext } from 'react';
import { Context } from './context';

function MyComponent() {
  const value = useContext(Context);

  return <span>{value}</span>;
}
Enter fullscreen mode Exit fullscreen mode

You can check out the demo here.

Does React context replace Redux?

Absolutely! And well, not quite.

For React beginners, Redux simplifies data sharing. Redux is bundled with React context, which enables easier passing of data.

However, if you’re not modifying the state and just passing it down your component tree, you don’t require Redux, a global state management library.

How to update the context value?

The React Context API doesn’t have a built-in way to update the context value from consumer components since it’s primarily designed to be stateless.

However, you can easily achieve this by incorporating a state management approach, such as using the useState() or useReducer() hooks. By doing so, you can provide an update function alongside the value in the context.

Although, it’s generally not recommended to update the context value due to performance concerns. and this leads us to the limitations of React context.

Read this awesome blog about how to use and update the context.

React context limitations

Let’s understand it by example. Suppose you’re passing down an object through your React context provider, and one of its properties gets updated. What happens next? Well, any component that consumes that context will re-render.

Now, this might not pose a performance problem in smaller applications with only a few state values that don’t change frequently (like theme data). However, it becomes problematic when you have numerous components in your component tree and need to perform multiple state updates.

A workaround for this is by creating a separate Context/Provider for each functional section that needs to share data among its components. This approach helps minimize the number of components that need to be rendered, as updates will only occur within specific sub-trees of your application.

Conclusion

Great job! By learning Context API, you’ve added a valuable skill to your toolkit. Now you can pass the value of the first component to the last component without disturbing the other components.

I hope this article has brought some new knowledge your way today. If you found it enjoyable and helpful, please don’t hesitate to give me a couple of claps! 👏

Please leave a comment with your feedback.

If you’d like to support me as a writer, consider Following me on Dev.to, and Connecting with me on LinkedIn.

Top comments (0)