# React Context
# Introduction
Certainly! Before diving a little bit into React Context, let's start by understanding the concept of state managers.
# What are state managers ?
State managers in React are tools or libraries that help manage the state of a React application. State is an important concept in React, as it allows components to store and manage data, and update the UI accordingly. State managers provide a way to manage and organize the application state in a centralized and scalable manner, making it easier to handle complex state interactions, share state between components, and manage state changes in a predictable and efficient way.
# What problems does it solve?
The purpose of state managers is to provide a robust and scalable solution for managing application state, particularly in large or complex applications. State managers provide a solution to avoid the issue of prop drilling, as they allow for centralized management of state that can be accessed by any component in the application, without the need to pass down props through multiple layers of components.
In summary, state managers in React are tools or libraries that help manage the application state in a centralized and scalable way.
# What is prop drilling?
Passing props is a great way to explicitly pipe data through your UI tree to the components that use it. But passing props can become verbose and inconvenient when you need to pass some prop deeply through the tree, or if many components need the same prop. The nearest common ancestor could be far removed from the components that need data, and lifting state up that high can lead to a situation called "prop drilling". These kind of situations could be resolved using Context.
# What is React Context ?
React Context is a built-in feature of React that allows data to be passed down through the component tree without having to explicitly pass it through props. It provides a way to share data across multiple components, regardless of their position in the component hierarchy. Context is particularly useful for managing global state, such as theme settings, user authentication status, or localization preferences, that needs to be accessed by multiple components in different parts of the application.
Using Context removes the necessity to pass props to many components, or if many components in your app need the same information.
Common use cases for Context:
- Theming
- Current account
- Routing
- Business app state
Context is typically used for information that is relevant to many components in an application, such as a user's authentication status, a theme or language preference, or any other shared state. Context is especially useful for passing data down to deeply nested components, where passing props through every intermediate component would be cumbersome.
Let's build a small app using React Context to see how it works and how we can use it to share a global theme state across the whole app.
# How to create a context ?
To manage state with React Context, you first need to create a Context object. You can do it using the React.createContext method. This creates a new context object that can be used to share data between components. The initial value for the context in this example is an object with two properties: themeMode (string value) and setThemeMode (function to change theme), both with default values.
import React from "react";
const ThemeContext = React.createContext({
themeMode: "light",
setThemeMode: () => {},
});
export default ThemeContext;
# Wrapping in a Provider
In the second step, we need to wrap our parent component with a Provider component from the created context, and pass in a value prop with the data we want to share. In this case, we create a theme object with a themeMode property of "light" and a setThemeMode as state setter, and pass it as the value for the ThemeContext.Provider.
import { useState } from "react";
import { SomeComponent } from "./SomeComponent";
import ThemeContext from "./ThemeContext";
import ThemeSwitcher from "./ThemeSwitcher";
import "./styles.css";
export default function App() {
const [themeMode, setThemeMode] = useState("light");
return (
<ThemeContext.Provider value={{ themeMode, setThemeMode }}>
<ThemeSwitcher />
<SomeComponent />
</ThemeContext.Provider>
);
}
# Accessing shared data with useContext hook
In the third step, we access the shared data in child components using the useContext hook from the React library. In the Header component, we use useContext to access the theme object from the ThemeContext, and use it to style the content of the component.
import React, { useContext } from "react";
import ThemeContext from "./ThemeContext";
const ThemeSwitcher = () => {
const { themeMode, setThemeMode } = useContext(ThemeContext);
const handleClick = () => {
setThemeMode(themeMode === "light" ? "dark" : "light");
};
const styles = {
backgroundColor: themeMode === "light" ? "#f5f5f5" : "#212121",
color: themeMode === "light" ? "#212121" : "#f5f5f5",
borderRadius: "50%",
fontSize: "2rem",
};
return (
<button style={styles} onClick={handleClick}>
{themeMode === "light" ? "🌑" : "🌞"}
</button>
);
};
export default ThemeSwitcher;
# Accessing data from anywhere else
In this simplified example, we use the useContext hook to access the themeMode property from the ThemeContext. We use this property to set the background color, text color, and other styles for the component. Finally, we render a simple message indicating which theme mode is being used.
import React, { useContext } from "react";
import ThemeContext from "./ThemeContext";
export const SomeComponent = () => {
const { themeMode } = useContext(ThemeContext);
const styles = {
backgroundColor: themeMode === "light" ? "#f5f5f5" : "#212121",
color: themeMode === "light" ? "#212121" : "#f5f5f5",
padding: "1rem",
borderRadius: "5px",
};
return (
<div style={styles}>
<p>This component uses the {themeMode} theme mode.</p>
</div>
);
};
And this is how the app looks like after running it:
In conclusion, React Context provides a simple way to share data across components in a React application. By creating a context using React.createContext(), wrapping components with a Provider, and using the useContext hook to access the shared data, you can effectively manage global state and eliminate the need for prop drilling, while also leveraging the benefits of functional components and hooks in modern React development.
A CodeSandbox example has been created to showcase the usage of React context. You can access the example by following this CodeSandbox link (opens new window).
TIP
If you have some doubts you can always check official React docs (opens new window)
By the way, if you're interested in exploring other options for state management in React, you could check out libraries like Redux (opens new window).