DEV Community

Cover image for A Guide to React Context 💫
Adyasha Mohanty
Adyasha Mohanty

Posted on • Edited on • Originally published at adyablogs.vercel.app

A Guide to React Context 💫

What is React Context 🤔?

The React Context provides a way to pass data through the component tree without having to pass props down manually to every level. In React, data is often passed from a parent to its child component as a property.

Context is like a global object to the React component sub-tree 🌐.

What problems does Context solve 😟?

  • In React applications let parent components pass data long to children components but issues arise when that data is meant to be used by children components multiple layers deep but not by immediate children of that parent component.

Let's look at the below diagram 📈.

Image1

Component A is clearly the main parent component with immediate children components B, C. These components can receive params from component A and pass that data to the children components, but what about a scenario where Component E needs data from Component A and that data is not needed in Component B then passing that data to Component B becomes redundant.

Props drilling, a term to describe when you pass props down multiple levels to a nested component, through components that don't need it.

This is the benefit of React context - it provides a cool way 😎 of making data readily available to every single child component in the React Application.

How do we use Context 😕?

As far we get to know that React context allows us to pass down and use (consume) data in whatever component we need in our React app without using props.

Using the new React Context API depends on four main steps:

🔸 Create Context using the createContext method. This function then returns an object with a Provider and a Consumer.

import React from 'react';

const AuthContext = React.createContext();
Enter fullscreen mode Exit fullscreen mode

🔸 Next, use the Provider component to wrap around the parent/main component.

🔸 Wrap child components in the Provider component and make it accept a prop called value. This value can be anything!

<AuthContext.Provider value={value}>
  <Demo />
</AuthContext.Provider>
Enter fullscreen mode Exit fullscreen mode

🔸 Use the Consumer component anywhere below the Provider in the component tree to get a subset of the state.

function Demo() {
  return (
    <AuthContext.Consumer>
      {value => <h1>{value}</h1>}
    </AuthContext.Consumer>
  );
}
Enter fullscreen mode Exit fullscreen mode

📌 Let's see the full example:

import React from 'react';

export const AuthContext = React.createContext();

export default function App() {
 return (
   <AuthContext.Provider value="Happy">
    <Demo />
   </AuthContext.Provider>
 )
}

function Demo() {
  return (
    <AuthContext.Consumer>
      {value => <h1>{value}</h1>} /* prints happy */
    </AuthContext.Consumer>
  );
}
Enter fullscreen mode Exit fullscreen mode

Above our App component, we are creating context with React.createContext() and putting the result in a variable, AuthContext.

  • In almost every case, you will want to export it as we are doing here because your component will be in another file.

Note that we can pass an initial value to our value prop when we call React.createContext().

  • The created context is an object with two properties: Provider and Consumer, both of which are components.

Things to keep note down what Provider actually do ✍️:

➡️ It holds one single javascript value that can be anything: an array, a function or an object.

➡️ It won’t cause its children to re-render: The context’s provider’s direct children won’t re-render every time the provider renders, but the consumers will.
This rule is only valid for re-renders caused by the provider internally (state), but if his parent re-renders (props), the provider’s children will re-render as well.

➡️ All subscribers will re-render when the context value changes.

  • In our App component, we are using AuthContext. Specifically AuthContext.Provider, To pass our value down to every component in our App, we wrap our Provider component around it and in this case, Demo.

  • On AuthContext.Provider, we put the value that we want to pass down our entire component tree. We set that equal to the value prop to do so. (here, Happy).

  • In Demo, or wherever we want to consume what was provided in our context, we use the consumer component: AuthContext.Consumer To use our passed-down value, we use what is called the render props pattern.
    It is just a function that the consumer component gives us as a prop. And in return for that function, we can return and use that value.

Another way of consuming context with the useContext hook.

📌 Here is the same example using useContext:

import React from 'react';

export const AuthContext = React.createContext();

export default function App() {
 return (
   <AuthContext.Provider value="Happy">
    <Demo />
   </AuthContext.Provider>
 )
}

function Demo() {
 const value = React.useContext(AuthContext);
 return <h1>{value}</h1>; 
}
Enter fullscreen mode Exit fullscreen mode

useContext accepts the context type as parameter and returns the context value of the nearest provider of that type. If there is no such provider, then the default context value will be returned.

Will app’s performance get impacted 💥?

🔹 In short, you app’s performance will decrease drastically if your provider does a lot of work, for example having a value that combines a lot of separate values, you will have a lot of consumers of the same provider, and they will all re-render.

🔹 When the provider’s wrapper re-renders due to an internal cause (may be state), its children won’t re-render, only a consumer will. It is like your provider’s value teleports from the provider to the consumers directly ignoring everything in between.

🔹 So, it is more than okay to have multiple contexts and providers.

What differs Redux from context API ?

As you can see, the concepts involved are actually not that different from Redux.

So does context replaces redux?

The answer is NO🙅.

Redux isn’t only a way to pass down props( teleports them), it allows persistence, supports middlewares, and has a lot more advantages.
My recommendation is to use Redux for complex global state management and Context for prop drilling.

As this article isn’t meant to talk about redux, so, I will drop some useful resources to read more about this comparison 👇.


In this article, we explored how we can easily use React Context instead of passing down props to share data between components 🚢.
Depending on your use case, you might prefer to use simple props, React Context or even a third-party library like Redux to share data between your components.

Keep coding 😉. Thank you for reading 💖.

Feel free to connect on Twitter :)

Top comments (13)

Collapse
 
adyasha8105 profile image
Adyasha Mohanty

Thanks Anjan!!

Collapse
 
vinaysehwag14 profile image
VinaySehwag14

I have so many doubts , you cleared all at once , Can you write abt how to use useContext with useReducer…

Collapse
 
adyasha8105 profile image
Adyasha Mohanty

Sure I will do it :D

Collapse
 
davidcam profile image
David Camarena

The most clear and understandable article about ReactContext I've read so far, so thank you + congrats!! Very nice one! :)

Collapse
 
adyasha8105 profile image
Adyasha Mohanty

Thank you so much, David!!

Collapse
 
meer profile image
Meer

Well explained.

Collapse
 
adyasha8105 profile image
Adyasha Mohanty

Thanks khalil :)

Collapse
 
lucaargentieri profile image
Luca Argentieri

Ty Adyasha, can you write a guide to Redux?

Collapse
 
adyasha8105 profile image
Adyasha Mohanty

Yeah sure!! I would definitely :)

Collapse
 
laimejesus profile image
LaimeJesus

Great article and great reading! Love the extra details about to how to handle state (Context vs Redux)

Collapse
 
adyasha8105 profile image
Adyasha Mohanty

Thank you Laime.

Collapse
 
vengateshtr profile image
Vengatesh TR

Good explanation. Thank you.

Collapse
 
adyasha8105 profile image
Adyasha Mohanty

Thank you Vegantesh!!