Use the useContext hook when there is a need to share states or functions between components without passing them as props. For example, sharing user data or managing themes across components.
Key takeaways:
React Context allows components to share state directly without prop drilling, improving code clarity and reducing manual prop passing.
It is integrated into React and requires no additional dependencies, making it straightforward and efficient for many use cases.
Hooks like useContext make it easier to manage the global state across components without prop drilling. This makes it easier to share data like themes or user states across components, streamlining your code and improving maintainability.
For apps with simpler state management needs, the React Context offers a cleaner and more straightforward solution than Redux. While Redux is powerful for complex apps, React Context works well when state updates are limited to a few components or involve only a handful of global variables.
React context simplifies state management in React applications by providing a mechanism to share data across components without manually drilling props. Instead of passing data step-by-step, Context allows components to access shared values directly, no matter how deeply nested in the component tree. Unlike traditional state management approaches, React context is lightweight and straightforward for specific use cases like themes, authentication, and localization.
React context addresses a common problem in React—prop drilling. Prop drilling occurs when data needs to be passed through multiple layers of components, even if only the deeply nested components require it. Context provides a solution by offering direct access to the shared state.
React Context relies on the Context API introduced in React 16.3. It involves three main steps:
Creating a context using the createContext method. This method creates a Context object and can optionally include a default value:
import { createContext } from 'react';const CustomThemeContext = createContext("defaultValue");
Using the Provider component to wrap components that need access to the Context. It supplies the data through the value prop.
<CustomThemeContext.Provider value="gray"><ChangeTheme /></CustomThemeContext.Provider>
Retrieve data using the useContext hook—a simpler way to consume context values, replacing the older Consumer component:
const themeData = useContext(CustomThemeContext);
Learn more React context, by trying this project, Markdown Editor Application in React Using Context APIs and Hooks.
Let's build an app with a React context to switch between light and dark themes. The theme value will be managed using React’s useState hook.
We will start with creating a context and providing it to a child component in our application.
import React, { createContext, useState } from 'react';// Create context with a default valueconst CustomThemeContext = createContext("light");function App() {const [backgroundTheme, setBackgroundTheme] = useState("light");return (<CustomThemeContext.Provider value={{backgroundTheme,setBackgroundTheme}}><ChangeTheme /></CustomThemeContext.Provider>);}export default App;
Line 1: We import useState and createContext from React.
Line 4: We use createContext to create a new context object, CustomThemeContext. We provide "light" as the default value. If no <Provider> is found above in the component tree, this value will be used when a component consumes the context.
Line 7: We declare a state variable called backgroundTheme with an initial value of "light".
Line 10: The CustomThemeContext.Provider makes the theme value (backgroundTheme) and the updater function (setBackgroundTheme) available to all child components. The value prop passes these two variables as an object {backgroundTheme,setBackgroundTheme}.
Line 12: ChangeTheme is a child component wrapped within the provider, meaning it will have access to the context values.
useContexthookNow, let’s create a component that consumes the theme context and allows users to toggle between themes.
import React, { useContext } from 'react';function ChangeTheme() {const { backgroundTheme, setBackgroundTheme } = useContext(CustomThemeContext);function changeTheme() {setBackgroundTheme((prevTheme) => (prevTheme === "light" ? "dark" : "light"));};return (<buttononClick={changeTheme}style={{background: backgroundTheme === "light" ? "#fff" : "#555",color: backgroundTheme === "light" ? "#000" : "#fff",}}>Switch to {backgroundTheme === "light" ? "Dark" : "Light"} Theme</button>);}
Line 4: We use useContext to access the backgroundTheme and setBackgroundTheme values from CustomThemeContext. Now, the ChangeTheme component has access to both the current theme and the function to change it.
Lines 6–8: We define a function, changeTheme that checks the current theme, prevTheme. If the theme is "light", it switches it to "dark", and vice versa.
Lines 11–19: We render a button with an onClick handler that triggers changeTheme when clicked. The button's style dynamically sets the background color based on the current theme. The button text shows the target theme (e.g., “Switch to Dark Theme” if the current theme is light).
Let's look at a working example by combining everything and executing the application.
Implement the useContext hook in a real-world application in this project, Build a Location Tracker Using Leaflet, ReactJS, and Express.js.
Apart from React context, we can also Redux to manage the global state of an application or a feature. Redux is a powerful tool for large-scale state management but comes with more boilerplate.
React context and Redux are popular tools for state management in React applications. While both aim to manage shared states effectively, they cater to different levels of complexity and use cases. Let's look at the differences in the table below.
Feature | React context | Redux |
Purpose | Manage simple, shared state like themes or user data. | Manage complex, global state with advanced features. |
Boilerplate | Minimal setup with the Context API. | Requires significant setup (actions, reducers, store). |
Data Flow | Unidirectional, using | Unidirectional, using dispatch and reducers. |
Performance Optimization | Needs manual memoization of context values. | Built-in mechanisms for optimizing re-renders. |
Scalability | Best for small to medium apps. | Suitable for large-scale applications. |
React context offers several benefits, particularly for smaller-scale applications.
No need to use external libraries, e.g., Redux, reducing dependencies and simplifying project setup.
Context eliminates the need to pass props manually through every component level.
Easy to understand and implement, especially with the useContext hook.
Works seamlessly with React's rendering model without adding significant overhead.
Despite its simplicity, React context has some limitations that may affect its suitability for large-scale applications.
Context re-renders all consuming components when the provider’s value changes. This can lead to performance bottlenecks in large trees.
Managing a complex state with Context alone can become cumbersome without middleware or advanced tools.
Debugging deeply nested components relying on multiple contexts can be challenging without specialized tools.
Unlike Redux, React context does not natively support middleware for asynchronous operations or side effects.
React context is a valuable tool for managing the global state in a React application. While it may not replace state management libraries like Redux, its simplicity and integration make it an excellent choice for many use cases. By following best practices and leveraging hooks, you can maximize the potential of React context in your projects.
Haven’t found what you were looking for? Contact Us