In React, if we want to pass props to a nested child component, we usually have to thread it through the child's ancestors like so:
function App() {
const data = "Hello world"
return <FirstAncestor data={data} />
}
function FirstAncestor(props) {
return <SecondAncestor data={props.data} />
}
function SecondAncestor(props) {
return <TargetComponent data={props.data} />
}
function TargetComponent(props) {
return <h1>{props.data}</h1>
}
This can be cumbersome if we have to pass props down to a deeply nested component in a large component tree.
One solution to this is by creating a Context in React usually located in a separate module, and consume it at any child component's level without threading it through its ancestors.
In this article, you'll learn:
What Context is in React
How to create it and,
How to consume it in any component at any level
What Context is
According to the documentation...
Context provides a way to pass data through the component tree without having to pass props down manually at every level.
Some benefits of using context include
Theming
Accessing the current user
Creating a context
We can create a context with React.createContext(defaultValue)
and export it for reuse throughout our app, like so:
// in UserContext.js
import React from 'react';
const UserContext = React.createContext("Jeffrey");
export { UserContext }
This context object can then be used in any component at any level by consuming it.
Consuming or using a context
Now to consume a context in a component, we need to wrap it in the context's Consumer
.
The Consumer
is a component derived from the context that takes a function as a child and passes the context object to be used by the component. Here's what it looks like:
import { UserContext } from './UserContext';
function App() {
return <First />
}
function Name() {
return (
<UserContext.Consumer>
{(contextValue) => {
return (
<p>{contextValue}</p>
)
}}
</UserContext.Consumer>
);
}
function FirstAncestor() {
return <SecondAncestor />
}
function SecondAncestor() {
return <Name />
}
As you can see above, we're not passing any props through the ancestors down to <Name />
in order to use the value of UserContext
. We can just use it directly and this simplifies our component tree greatly
For a class component, we can use a Context by assigning it's
contextType
property to the context and then retrieve it in the render function by callingthis.context
. Like so:
import { UserContext } from './UserContext'; class Name extends React.Component { render() { let userName = this.context; return ( <p>{userName}</p> ); } } Name.contextType = UserContext; export default Name;
Setting context values
Besides using the default values we set when creating the context object, we can change the value of the context used by a component by wrapping it in the context's Provider
and specify a new value by changing it's value
prop.
This way, a component can use a different context data from other components, by consuming the value of the nearest context Provider
in the component tree. Here's what it looks like:
import { UserContext } from './UserContext';
function App() {
return (
<>
<UserContext.Provider value="Martins">
<Name />
</UserContext.Provider>
<Name />
</>
)
}
function Name() {
return (
<UserContext.Consumer>
{(contextValue) => {
return (
<p>{contextValue}</p>
)
}}
</UserContext.Consumer>
);
}
This renders "Martins" first to the screen and then "Jeffrey". Notice that the original context did not change.
The reason this happens is because the first <Name />
component wrapped by <UserContext.Provider>
consumes the value
of that provider while the second one simply uses the default value of UserContext
.
This way, we can reuse the same component and render something entirely different without much changes to its structure
Accessing context values with useContext hook
To access context values in your component besides rendering it, we need to use the useContext
hook, passing it our context object and retrieving the context values. Like so
import { UserContext } from './UserContext';
import { useContext } from 'react';
function App() {
const userName = useContext(UserContext);
console.log("The user's name is: ", userName)
return (
<p>Check the console for the user's name</p>
)
}
With this, we can do anything we want with the context object
useContext
returns a copy of the context values, not a reference to the main context since it's immutable
Conclusion
In this article, I believe you've understood what Context is in React, and how to use it to simplify your component tree.
Thanks for reading, and I hope this article helps you. If you have any questions, you can drop a comment below and I'll reply.
Also, you can connect with me online via any of these platforms
Have a nice day.