Introduction
In React, passing data from a parent component to a deeply nested child component can become cumbersome and lead to code that is hard to maintain and understand. As we have to pass data from every level, this is called prop drilling.
The useContext solves this problem. It simplifies the process of sharing data across different components without the need for prop drilling. It enables us to pass data to any nested child component without passing through every level.
In this article, we will see how to create context and use the context value in the child components.
Using the useContext hook
There are three steps we need to follow to use it.
Creating the context:
In the first step, we import the
createConext()
function from React. It is used to create a context instance.import { useContext } from 'react'; // create a context instance export const MyContext = useContext('some default value');
Passing the context value:
In the second step, we pass the data to child components.
The
MyContext
instance that we created in the first step has aMyContext.Provider
component that is used to pass the data to child components.import { createContext } from "react"; // create context instance export const MyContext = createContext("some default value"); const App = () => { const data = "Hello world"; return ( // passing down the data value <MyContext.Provider value={data}> // components that want to consume data... </MyContext.Provider> ); }; export default App;
In this example, MyContext.Provider
component accepts a value
prop, which is used to pass the data to child components.
All the components that want to consume the data should be wrapped with the MyComponent.Provider
component.
Consuming the data in child components:
To consume the data value in child components, we first need to import the context instance that we created in the first step and the
useContext
hook from React.import { useContext } from 'react';
Then we pass the context instance to the useContext hook, which returns the data that we passed to the value
props of the MyComponent.Provider
component.
import { useContext } from 'react';
const MyChildComponent = () =>{
const data = useContext(MyContext);
return <p> {data} </p>
}
In this example, we pass the MyContext
instance to the useContext
hook which returns the data value.
The useContext
hook automatically re-renders the component when the data value changes.
Use cases
Let's consider an example where we want to implement the theming feature in our app.
Define the theme context:
//App.js import React, { createContext } from 'react'; // create an instanc of context export const ThemeContext = createContext();
Wrap our components with
ThemeContext.Provider
component:// App.js import React, { createContext } from 'react'; export const ThemeContext = createContext(); function App() { return ( // Wrapping components with ThemeContext.Provider <ThemeContext.Provider> <MyComponent /> {/* Other application components */} </ThemeContext.Provider> ); } export default App;
Passing down the theme data to components:
// App.js import React, { createContext, useState } from 'react'; export const ThemeContext = createContext(); // Wrap components with ThemeContext.Provider function App() { const [theme, setTheme] = useState('light'); const toggleTheme = () => { setTheme( prevTheme => { if(prevTheme === 'light') return 'dark'; else return 'light'; }); }; return ( // passing down theme data to components <ThemeContext.Provider value={{ theme, toggleTheme }}> <MyComponent /> {/* Other application components */} </ThemeContext.Provider> ); }
In this example, we are passing down a data object with two properties:
theme
andtoggleTheme
.Any child component can access that object and can access the current
theme
value, and can also toggle that usingtoggleTheme
method.Consuming the Theme context value:
// App.js import React, { createContext } from 'react'; export const ThemeContext = createContext(); // Wrap components with ThemeContext.Provider function App() { const [theme, setTheme] = useState('light'); const toggleTheme = () => { setTheme( prevTheme => { if(prevTheme === 'light') return 'dark'; else return 'light'; }); }; return ( // Wrapping components with Cotext provider & passing data <ThemeContext.Provider value={{ theme, toggleTheme }}> <MyComponent /> {/* Other application components */} </ThemeContext.Provider> ); } // Consume theme context value function MyComponent() { const { theme, toggleTheme } = useContext(ThemeContext); return ( <div> <button onClick={toggleTheme}>Toggle Theme</button> <p>Current Theme: {theme}</p> </div> ); }
In this example,
MyComponent
consumes the theme data using the useContext hook. The useContext takesThemeContext
as an argument and returns the theme data that we passed in theThemeContext.Provider
component.
Conclusion
In this article, we covered the basic concepts of the useContext hook and how it can be used to share data across components without the need for prop drilling.