Context is translated into Context, which is a common concept in the programming field. In the React official documents, Context is classified as the Advanced part, which belongs to the React high-level API. So let’s talk about the React context.

To be clear, all Context apis mentioned in this article refer to the new Context API. The new Context API was introduced in react version 16.3. The context API before this release is called the old context API. They both address the same problem: “prop-drilling of props across the component hierarchy.”

The official definition of Context

The React documentation website does not give a definition of what a Context is, but rather describes the Context in which it is used and how it is used.

Context provides a method to pass data across the component tree without having to manually add props for each layer of components.

When you don’t want to pass props or states in the component tree, you can use Context to pass data across the hierarchy.

With Context, data can be passed across components.

How to Use Context

To use the Context API, follow these three steps:

  1. First, callconst ThemeContext = React.createContext()To create a context object instance;
  2. Second, use<ThemeContext.Provider value={someValue}>Component to declare any data you want to pass;
  3. Finally, pass the render props paradigm<ThemeContext.Consumer>{(someValue)=> .... }</ThemeContext.Consumer>Or hookconst theContextValue = useContext(ThemeContext)To retrieve the data that you want to read for consumption.

In the new implementation of the Context API, whenever a child component subscribing to data held by an instance of the Context object changes, the child component will be updated regardless of what the upper-layer component does. For example, in the following code, we manually style a button component with a “theme” property:

class App extends React.Component { render() { return <Toolbar theme="dark" />; }} function Toolbar(props) {// The Toolbar component accepts an extra "theme" property and passes it to the ThemedButton component. // If every single button in the application needs to know the value of theme, this would be very troublesome, because you would have to pass this value through all the components. return ( <div> <ThemedButton theme={props.theme} /> </div> ); } class ThemedButton extends React.Component { render() { return <Button theme={this.props.theme} />; }}Copy the code

Using context, we can avoid passing props through an intermediate element:

// Context allows us to pass values deep into the component tree without explicitly passing them through each component. // Create a context for the current theme (" light "is the default). const ThemeContext = React.createContext('light'); Class App extends react.ponent {render() {// Use a Provider to pass the current theme to the following component tree. // This value can be read by any component, no matter how deep. // In this example, we pass "dark" as the current value. return ( <ThemeContext.Provider value="dark"> <Toolbar /> </ThemeContext.Provider> ); }} // The intermediate component no longer has to specify that the theme is passed down. function Toolbar() { return ( <div> <ThemedButton /> </div> ); } class ThemedButton extends react.ponent {// Specify contextType to read the current theme context. // React will look up to the nearest theme Provider and use its value. // In this example, the current theme value is "dark". static contextType = ThemeContext; render() { return <Button theme={this.context} />; }}Copy the code

Think of Context as the component scope

As anyone who uses React knows, a React App is essentially a tree of React components. Each React component is a node in the tree. In addition to the root node of the App, every other node has a chain of parent components.

For example,<Child />The parent component chain is<SubNode /><Node /><App />.<SubNode />The parent component chain is<Node /><App />.<Node />The parent component chain has only one component node, which is<App />.

These tree-connected component nodes actually form a Context tree.

Have know JS scope chain concept developer should all know, JS code block during execution, will create a corresponding scope chain, the scope chain recording the runtime JS code block during execution can access the activities of the object, including variables and functions, JS program through the scope chain access to the code block variables and functions of the internal or external.

Using the JS scope chain analogy, the React component provides a Context object that is actually a scope for children to access, and the properties of the Context object can be thought of as an active object on the scope. Since the Context of a component is composed of the Context object returned by all components on the parent node chain via getChildContext(), the Context is a property that a component can access to the Context provided by all node components on the parent node chain.

Before you use Context

As the React high-level API, React does not recommend that we use Context as a priority. The main application scenario of Context is that many components at different levels need to access the same data. Use with caution, as this makes the component less reusable.

If you just want to avoid passing on attributes,Component CompositionSometimes it’s a better solution than a context.

For example, consider a Page component that layers down the User and avatarSize properties so that the deeply nested Link and Avatar components can read these properties:

<Page user={user} avatarSize={avatarSize} /> // ... Apply colours to a drawing gives... <PageLayout user={user} avatarSize={avatarSize} /> // ... Apply colours to a drawing gives... <NavigationBar user={user} avatarSize={avatarSize} /> // ... Apply colours to a drawing gives... <Link href={user.permalink}> <Avatar user={user} size={avatarSize} /> </Link>Copy the code

If at the end of the day only the Avatar component really needed user and avatarSize, passing these two props at different levels would seem redundant. And once the Avatar component needs more props from the top-level components, you have to add them one by one in the middle tiers, which can get very cumbersome.

One solution without context is to pass the Avatar component itself, so the intermediate component doesn’t need to know the user or avatarSize props:

function Page(props) { const user = props.user; const userLink = ( <Link href={user.permalink}> <Avatar user={user} size={props.avatarSize} /> </Link> ); return <PageLayout userLink={userLink} />; <Page user={user} avatarSize={avatarSize} /> //... Apply colours to a drawing gives... <PageLayout userLink={... } / > / /... Apply colours to a drawing gives... <NavigationBar userLink={... } / > / /... Apply colours to a drawing gives... {props.userLink}Copy the code

With this change, only the top Page component needs to know how the Link and Avatar components use User and avatarSize.

This inversion of control for components reduces the number of props to pass in your application, which in many cases will make your code cleaner and give you more control over the root component. However, this doesn’t work in every scenario: this kind of lifting logic higher up the component tree makes those higher-level components more complex and forces lower-level components to fit into a format that you probably don’t want.

And your component is not limited to receiving a single subcomponent. You might pass more than one child component, or even encapsulate separate “slots” for those children, as the documentation here lists

function Page(props) {
  const user = props.user;
  const content = <Feed user={user} />;
  const topBar = (
      <Link href={user.permalink}>
        <Avatar user={user} size={props.avatarSize} />
  return (
Copy the code

This pattern is sufficient to cover many scenarios where you need to decouple child components from their directly associated parent components. If the child component needs to communicate with the parent component before rendering, you can further use the render props.

However, sometimes components at different levels in the component tree need to access the same batch of data. Context allows you to “broadcast” this data to all components in the component tree, all of which have access to the data and to subsequent updates. Common scenarios for using context include managing the current locale, theme, or some cached data, which is much simpler than the alternative.


  • Compared to props and state, React Context allows for cross-hierarchy communication between components.

  • The use of the Context API is based on the producer-consumer pattern. The Provider receives a value attribute and passes it to the consuming component. A Provider can have relationships with multiple consumer components. Multiple providers can also be nested, with the inner one overwriting the outer data.

  • It is not recommended to use Context in an App. However, if the component development process can ensure that the component is cohesive, controllable and maintainable, does not break the dependency of the component tree, and the impact scope is small, you can consider using Context to solve some problems.

  • Context only considers the passing and sharing of static data across component hierarchies and does not consider status updates.

  • You can think of a Context as the scope of a component, but you need to pay attention to the controllability and scope of the Context. Before using the Context, analyze whether it is really necessary to use it to avoid the side effects of overuse.

  • You can use the Context as a medium to share data at the App level or component level.