Context API in React
In React, when we are building an application, there can be some properties such as Title, or color that will be configured at the topmost component in <App/>. These properties will be passed down to its child components & also grandchild components & used by them at their levels. However, these properties have to be passed from the parent down to the lowermost child component, through all the intermediate components, which are not even using them.
Considering an example below, a MenuItem component.
import React from 'react';
const App = () => {
return <MainMenu colour="green" language="en" />;
}
function MainMenu(props) {
return( <MenuElement
color={props.colour}
menuLanguage={props.language}/>
)}
function MenuElement(props) {
return( <div>
<p>Theme colour: {props.color}</p>
<p>Locale: {props.menuLanguage}</p>
</div> );
}
export default App;
|
In the above example <MenuElement> component may need values of color for styling purpose, and language for the locale. But these properties had to be passed through <MainMenu/> component, even if these are not used in <MainMenu/>.
<App/> --> <MainMenu/> --> <MenuElement/>
Hence, these global properties, need to be mapped as props from intermediate child components even though it’s not being used in-between. This mechanism is called props drilling and it represents the redundant mapping of props for complex applications for multiple properties.
“The Context provides us a way to pass the data through the component tree without having to pass props down manually at each & every level.” → React Docs
React’s Context API is introduced to resolve the issue of props drilling, where a higher-order component’s context can be accessed by a child component without having to map the props in intermediate components.
Starting by creating a context, where a default value should be passed to initiate.
const MenuContext = React.createContext({ lang: 'en' }); |
This context object so created has Provider and Consumer with it. Or it can also extract these properties separately.
--- Can be used in MenuContext.js --- |
For our context value to be addressed at lower-level components, context should be attached to a higher-level component. Context. The provider will wrap this component, and the current value is attached to it as value.
const App = () =>
<MenuContext.Provider value={{ lang: 'fr' }}>
<MainMenu/>
<MenuContext.Provider />
|
Here, value is not passed as props to <MainMenu/> component, avoiding props drilling. Instead of using <MenuContext.Provider>,
We can also use <MenuProvider value=""> as above if imported from an external file.
Getting context by Context Consumer:
Consumers can be used to access the context provided from above.
const MenuElement = () =>
<MenuContext.Consumer>
{ value =>
<p>Locale: {value.lang}</p>
}
</MenuContext.Consumer>
|
As in context providing an example, the consuming component is also wrapped in <MenuContext.Consumer>. And value passed to <MenuContext.Provider> can be accessed as above.
Now, we can refactor our code using Context in the following way,
import React from 'react';
const MenuContext = React.createContext({ colour: 'blue', lang: 'en' });
const App = () =>
<MenuContext.Provider value={{ colour: 'blue', lang: 'fr' }}>
<MainMenu/>
</MenuContext.Provider>;
function MainMenu() {
return <MenuElement/>
}
const MenuElement = () =>
<MenuContext.Consumer>
{ value =>
<div>
<p>Theme colour: {value.colour}</p>
<p>Locale: {value.lang}</p>
</div>
}
</MenuContext.Consumer>
export default App;
|
Hence, we can use the passed context in whichever component we wish to , without getting it drilled through the intermediate components.