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 📈.
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();
🔸 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>
🔸 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>
);
}
📌 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>
);
}
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
andConsumer
, 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 ourvalue
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 thevalue
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 aprop
. And in return for that function, we can return and use thatvalue
.
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>;
}
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 👇.
- Answer on StackOverflow.
- Dan’s post about You Might Not Need Redux.
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.
%[INVALID_URL]Keep coding 😉. Thank you for reading 💖.
Feel free to connect on Twitter :)