Context
Context provides a way to pass data through the component tree without having to pass props down manually at every level.
In a typical React application, data is passed top-down (parent to child) via props, but such usage can be cumbersome for certain types of props (e.g. locale preference, UI theme) that are required by many components within an application. Context provides a way to share values like these between components without having to explicitly pass a prop through every level of the tree.
When to use context
Context is designed to share data that can be considered "global" for a tree of React components, such as the current authenticated user, theme, or preferred language.
For example, in the code below we manually thread through a "theme" prop in order to style the Button component:
class App extends React.Component {
render() {
return <Toolbar theme="dark" />;
}
}
function Toolbar(props) {
// The Toolbar component must take an extra "theme" prop
// and pass it to the ThemedButton. This can become painful
// if every single button in the app needs to know the theme
// because it would have to be passed through all components.
return (
<div>
<ThemedButton theme={props.theme} />
</div>
);
}
class ThemedButton extends React.Component {
render() {
return <Button theme={this.props.theme} />;
}
}
Using context, we can avoid passing props through intermediate elements:
// Create a context for the current theme (with "light" as the default).
const ThemeContext = React.createContext("light");
class App extends React.Component {
render() {
// Use a Provider to pass the current theme to the tree below.
// Any component can read it, no matter how deep it is.
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
}
// A component in the middle doesn't have to pass the theme down explicitly anymore.
function Toolbar() {
return (
<div>
<ThemedButton />
</div>
);
}
class ThemedButton extends React.Component {
// Assign a contextType to read the current theme context.
// React will find the closest theme Provider above and use its value.
static contextType = ThemeContext;
render() {
return <Button theme={this.context} />;
}
}
Context Limitations
Context is not made for every scenario, it has a few limitations:
- Context is not optimized for high frequency changes (e.g. changes multiple times per second)
- You could use something like Redux instead
- Context shouldn't be used to replace ALL component communications and props
- Components should still be configurable via props and short "prop chains" might not need replacement
API
React.createContext
const MyContext = React.createContext(defaultValue);
Creates a Context object. When React renders a component that subscribes to this Context object it will read the current context value from the closest matching Provider
above it in the tree.
Context.Provider
<MyContext.Provider value={/* some value */}>
Every Context object comes with a Provider React component that allows consuming components to subscribe to context changes.
The Provider component accepts a value
prop to be passed to consuming components that are descendants of this Provider. One Provider can be connected to many consumers. Providers can be nested to override values deeper within the tree. All consumers that are descendants of a Provider will re-render whenever the Provider’s value
prop changes. Changes are determined by comparing the new and old values using the same algorithm as Object.is.
Context.Consumer
<MyContext.Consumer>
{value => /* render something based on the context value */}
</MyContext.Consumer>
A React component that subscribes to context changes. Using this component lets you subscribe to a context within a function component. Requires a function as a child. The function receives the current context value and returns a React node. The value
argument passed to the function will be equal to the value
prop of the closest Provider for this context above in the tree.
Using context via Hook
When we are working with functional components we will want to use the useContext
hook. More info here.