preface

Context provides a way to share these values between components without having to explicitly pass a prop at each level of the tree.

In general, it is not recommended to use it in situations where you are not absolutely sure it is good and necessary.

However, we still use it indirectly, as many official dependencies are used, such as react-redux, mobx-react, and react-router. When we need its functionality, we rely more on third-party libraries rather than writing the context by hand. However, still need to understand it, with some of its dependent library source code understanding is very helpful.

import React, { Component } from 'react';

class Grandpa extends Component {
    state = {
        info: 'Information for the GrandPa component'
    }
    render() {
        return( <div> <Father info={this.state.info}/> </div> ); } } class Father extends Component { render() { return ( <div> <Son info={this.props.info}/> </div> ); }} class Son extends Component {render() {return (<div>, this.props. Info} </div>); } } export default Grandpa;Copy the code

Final page output:

I am the Son component and get the message: GrandPa componentCopy the code

We’ll see that the downside is passing values one layer at a time. If there are more layers and more data, the code will look messy. If one of the middle components forgets to pass values, it’s almost done; Also, the Father component doesn’t use the info value, it just passes it to the Son component.

If we use context, we can solve the problem of constantly passing values in this hierarchy.

React V16.3.0 context is an old context and a new context.

The older the Context API

So let’s talk about the old Context API

Change the code to the following:

import React, { Component } from 'react';
import PropTypes from 'prop-types';

class Grandpa extends Component {
    state = {
        info: 'Information for the GrandPa component'
    }
    getChildContext () {
        return { info: this.state.info }
    }
    render() {
        return (
            <div>
                <Father/>
            </div>); }}// Declare the Context object properties
Grandpa.childContextTypes  = {
    info: PropTypes.string
}

class Father extends Component {
    render() {
        return (
            <div>
                <Son/>
            </div>); }}class Son extends Component {
    render() {
        return (
            <div>I am the Son component and get the message: {this.context.info}</div>); }}// Declare according to the agreed parameter type
Son.contextTypes  = {
    info: PropTypes.string
}
export default Grandpa;
Copy the code

The PropTypes type check can also be written as follows

class Grandpa extends Component {
    static childContextTypes = {
        info: PropTypes.string
    }
    state = {
        info: 'Information for the GrandPa component'
    }
    getChildContext () {
        return { info: this.state.info }
    }
    render() {
        return (
            <div>
                <Father/>
            </div>); }}Copy the code

Type checking is performed on both the context values that need to be sent out and the context values that need to be received.

This API is probably fine to use normally, but if one of the middle components uses the shouldComponentUpdate method, it’s likely to cause problems.

The hierarchy of the three components is as follows

<GrandPa>
    <Father>
        <Son/>
    </Father>
</GrandPa>
Copy the code

If clicking on the GrandPa component Settings button updates the value of the info, that is, updating the Context: with the this.setstate ({info: ‘change value ‘}) method, then

  • The GrandPa component sets the new Context value through setState and triggers the child component to rerender.
  • The Father component is rerendered.
  • The Son component is re-rendered and gets the updated Context.

Suppose you add a function to the Father component

shouldComponentUpdate () {
    return false
}
Copy the code

Since Father doesn’t depend on any value, we default to not having to rerender it. However, this will result in the Son component not being rerender, meaning that the latest Context value cannot be retrieved.

Such uncertainty is completely out of the target component’s control, meaning that the target component cannot guarantee that it will receive the updated Context value every time. This is a big problem with older apis.

The new API solves this problem. Let’s look at the new API

The new Context API

New Context adds the creactContext() method to create a Context object. This object contains two components, one is a Provider and the other is a Consumer.

  1. The Provider and Consumer must come from the same Context object, that is, a Context created by react.createcontext ().
  2. The react.createcontext () method takes a default value that is used when there is no Provider in the Consumer outer shell.
  3. The Provider component uses the Object.is method to determine whether the prop value has changed. When the prop value changes, the corresponding Consumer component in its internal component tree receives the new value and rerenders it. This process is not affected by the shouldComponentUpdete method.
  4. The pattern in which the Consumer component receives a function as a children prop and generates a tree of components using the return value of that function is called the Render Props pattern.

usage

  1. So let’s first create a context object

The React. CreateContext method is used to create a Context object. This object contains the Provider and Consumer properties, which are the React components.

const InfoContext = React.createContext(' ');
Copy the code
  1. Use the Provider component to generate a context
class Grandpa extends Component {
    state = {
        info: 'Information for the GrandPa component'
    }
    render() {
        return (
            <InfoContext.Provider value={{ info: this.state.info}} >
                <Father/>
            </InfoContext.Provider>); }}Copy the code
  1. Use the Consumer component to get the value of the Context object
class Son extends Component {
    render() {
        return (
            <InfoContext.Consumer>
            {
                value => {
                    return <div>I am the Son component and get the message: {value.info}</div>}}</InfoContext.Consumer>); }}Copy the code