preface

In a typical React application, data is passed top-down (from parent to child) via the props property. But this approach is extremely cumbersome for certain types of properties (locale preferences, UI themes, for example) that are required by many components in your application. In this case, Context provides a way to share such values between components without explicitly passing props layer by layer through the component tree.

Today we will use this article to talk about Context, understand the daily use of Context, internal principles and use in common tool libraries.

The directory structure of this article is as follows:

  • Context usage and principle
    • Use the Context
    • The principle of analytic
  • Context is used in common tool libraries
    • Context is used in React-redux
    • Use Context in react-router-dom
  • Write in the last

Context usage and principle

The use of a Context simply means that the parent component provides a Context object for children (and children’s children, etc.) to use. When the value of the Context object changes, the child components of the Context object (and the child components of the child components, etc.) are used to trigger updates and rerender.

Use the Context

There are three steps to using Context:

  1. Build the Context object;

    To use a Context in react, we need to create a Context object using the createContext method provided by React.

    const Const = React.createContext();
    Copy the code

    The Context object has three key properties, _currentValue, Provider, and Consumer.

    Context._currentValue, which corresponds to the Context used by the child components, defaults to undefined. When using createContext, we can pass in an initial value, and _currentValue is initialized with the passed initial value.

    Context values used in child components are retrieved from context._currentValue.

    Context.Provider, react component that updates context. _currentValue and notifies child components that use the Context object to do so.

    Context.Consumer, react components that pass context. _currentValue to child components and subscribe to changes to context. _currentValue.

    The subscription, context._currentValue changes, and any child components that use the Context need to be updated and re-rendered.

  2. The parent component imports the Context object into the React application for its children to use;

    Once the Context object is built, the next thing to do is introduce the Context object into the React application for subcomponents to subscribe to.

    With context. Provider, we can introduce the Context object into the React application as follows:

    <Context.Provider value={value}>
        <Child />
    </Context.Provider>
    Copy the code

    The Provider receives a value property, and the value of the value is used to update context._currentValue. When the value of value changes, all child components that use Context are notified of the update.

  3. The child component gets the value of the Context object using;

    Finally, we need to get the context._currentValue value used in the child component.

    Context._currentValue can be obtained in one of the following ways:

    • contextType

      By defining a static contextType property for the class component, we can access the context._currentValue value from the context property in the class component instance.

      Specific usage is as follows:

      import Context from './context.js'
      class Child extends React.Component {
          static contextType = Context
          render() {
              return <div>{this.context}</div>
          }
      }
      Copy the code

      The class component reads context. _currentValue during rendering and initializes the Context property of the component instance with the read Context value.

      ContextTye mode has great limitations and has the following disadvantages:

      1. Applies only to class components;

      2. You can only use one Context object at a time;

    • useContext

      React provides the useContext hook to access the context._currentValue value in a functional component.

      Specific usage is as follows:

      import Context1 from './context1.js'
      import Context2 from './context2.js'
      function Child(props) {
          const context1 = React.useContext(Context1)
          const context2 = React.useContext(Context2)
          
          return ...
      }
      Copy the code

      The return value of useContext hook is context._currentValue.

      In contrast to contextType, useContext can use multiple Context objects, but only for functional components.

    • Consumer subscription

      In addition to contextType and useContext, we can also use Consumer to access context._currentValue values in child components.

      Specific usage is as follows:

      Import Context1 from './context1.js' import Context2 from './context2.js' < context1.consumer > // Context1 is _currentValue {Context1 => (< context2. Consumer> // Context2 is context2. _currentValue {Context2 => <Child context1={context1} context2={context2} /} </Context2.Consumer> )} </Context1.Consumer>Copy the code

      The Consumer approach works with functional and class components, and you can use multiple Context objects.

The principle of analytic

When we get contextType, useContext, or Consumer for a child component, we subscribe to the Context object.

During component rendering, React builds a virtual node-Fiber node object for each component. If the child gets context._currentValue using contextType, useContext, or Consumer, The corresponding Context object is stored in the Dependencies list of the Fiber Node object.

When the parent component changes the value of the context. Provider property, the context. Provier component is updated. During the update, the dependencies list of all child component virtual nodes is iterated to check whether the current Context object is included in the dependencies list. If so, force the child component to update, re-render, and get the latest context._currentValue.

Note that all three methods need to be wrapped in context. Provier, otherwise they will not work.

Context is used in common tool libraries

Context is widely used in react applications. The most common contexts are react-redux and react-router-dom.

Context is used in React-redux

React-redux allows you to use Redux in React applications.

With React-Redux, we can easily access the state of the store object in the component, change the state through store.dispatch, and then notify the component that uses store.state to update.

When react-Redux is used, the components that need to access stores must be wrapped in the Provider component provided by React-Redux.

The reactredux. Provider uses the Context in its implementation. It builds a Context object using react.createcontext, and the store object Redux builds is stored in context._currentValue, We then use context. Provider to introduce the Context object into the React application for subcomponents to subscribe to. All container components wrapped by Reactredux.provider (or components that use hooks) can get store objects from the Context.

Use Context in react-router-dom

With react-router-dom, we can establish mappings between routes and components (pages). When switching routes, the matching components (pages) are rendered to their respective locations.

React-router-dom also uses Context in its implementation.

When react-router-DOM is applied, the BrowserRouter(HashRouter) component is rendered first, then the Router component, and finally the Route component. When the Router component is rendered, the component instance is built and state.location is initialized. When the page jumps, the setState method is used to update the state. Location of the Router component instance to trigger the update of Router component, Route component and page component.

When react-router-dom is used, a Context object is constructed using react. createContext. The history object for page hops, the Location object for page URL information, and so on are stored in context._currentValue. The Router component uses context. Provider to introduce the Context object into the React application during rendering. The Route component subscribes to the Context via context.consumer during rendering, and passes context._currentValue to the page component via props.

When the page jumps, the Router component rerenders, causing the Context.provider component to rerender, and then notifies all Route components subscribing to the Context to force a new render, rematch, and render the matching page component.

Write in the last

So that’s the end of the Context. Finally, let’s summarize the key points to note when using Context:

  1. To use a Context, you need to first build the Context object through React. CreateContext.

  2. You use context. Provider to introduce the Context into the React application.

  3. All components that use the value of Context must be wrapped in context.provider.

  4. When the value of context. Provider changes, all components that use Context are forced to update it.