A new API must be created to solve one or a class of problems.

The problem with the old context

As we all know, one of the most important ideas recommended by React is one-way data flow. The entire React application follows the direction of data flow from top to bottom. As a result, in the case of nested multilayer components, the data of the parent component must pass through the props of the multilayer intermediate component if it is to be transmitted to the lowest component, resulting in a large number of redundant props declarations (called the props drilling problem).

Both the old and new context are used to solve the problems of props drilling. However, context before React 16.3 broke the fractal architecture idea of React.

Fractal means that any part of the React component tree can be directly run as a sub-tree.

But this idea is broken if you use the old context syntax:

enter code here
class Button extends React.Component {
    render() {
        return (
            <button style={{color: this.context.color}}></button>
        )
    }
}
Button.contextType = {
    color: PropTypes.string
}

class Message extends React.Component{
    getChildContext() {
        return {color: 'red'}
    }

    render() {
        return (
            <Button />
        )
    }
}

Message.childContextTypes = {
    color: PropsTypes.string
}
Copy the code

In the code above, the parent getChildContext and the child this.context are very magic and violate the fractal idea.

Fatal flaw in the old context

In addition to the above fractal violation of context, there is a fatal flaw that affects the functionality.

The flaw is that if a component returns false in shouldComponentUpdate during context passing, the following component will not be able to rerender, so that the new context value cannot be updated to the following component.

For example,

<A>
    <B>
        <C>
        </C>
    </B>
</A>
Copy the code

If the middle B component returns false in shouldComponentUpdate, the C component will fail to update.

The new context

A new API must be created to solve one or a class of problems.

With this in mind, it’s easy to understand why React 16 introduced the new Context API to address the above issues and shortcomings of the old context.

The new Context provides the createContext method to create a Context object with provider producer and consumer properties.

Usage three steps: 1. Create a context

const ColorContext = React.createContext('red'); / / red by defaultCopy the code

2. The parent component uses Provider

class Message extends React.Component {
    state = {
        color: 'green'
    }
    
    render() {
        return (
            <ColorContext.Provider value={this.state.color}>
                <Button />
            </ColorContext.Provider>
        )
    }
}
Copy the code

3. The child component uses Consumer

class Button extends React.Component {
    render() {
        return (
            <ColorContext.Consumer>
                {
                    value => 
                    (<span style={{color: value}}></span>)
                }
            </ColorContext.Consumer>
        )
    }
}
Copy the code

The new API declaratively expresses which context object providers or consumers are used by the component, thus conforming to the fractal idea of react.

In addition, the new API no longer relies on shouldComponentUpdate. The Provider uses object. is to determine if the props are changing, and notifies the corresponding consumer component of the new value if it does.

The problems and defects of the older API are resolved.

The context and the story

Redux, as a heavyweight solution for inter-component communication, dominates the React data management ecosystem.

After the new context appeared, the community began to question whether to use the new context instead of Redux.

Before we answer that question, we can take a quick look at the redux and React-Redux principles.

React with the story

The complexity of terminal applications comes from a large number of irregular interactive and asynchronous actions. These actions change the state of the application all the time.

Redux is designed to make state changes clear and reproducible to developers.

Redux is only responsible for managing the Store data warehouse, but how do you pass the data in the Store to components for use? That’s where react-Redux comes in.

We won’t go into the syntax of redux and React-Redux in detail here, but we know that there are two core steps to using React-Redux:

  1. Wrap the root component with a provider
  2. Connect the child component to the store using Connect

Here we find the familiar noun provider.

Yes, it is the context.provider mentioned above. React -redux uses the React context syntax, passing store as the context value.

The connect method then takes the value of store from the context and subscribes to store changes, and finally passes the value to the business component via props.

Fussiness and standardization

After a brief introduction to redux and React-Redux, we can see that redux is the equivalent of Context + data flow management.

In other words, Context is a much lighter version of the data management solution. If your application itself is not complex and just needs a place to store global data, then the context will probably suffice.

However, as the application complexity increases, so does the difficulty of managing complex contexts. Using the design philosophy and API of the Redux convention at this point can help keep complex applications developed by multiple people clear and disciplined.

In summary, Redux’s verbose template code corresponds to the concise API of context, and the former specification corresponds to the flexible and messy context.

Technology has no silver bullet, only according to the specific project to carry out the selection of technology is the most appropriate.

The appendix

Attached is a list of redux best practices compiled by the community for better understanding of Redux’s design philosophy:

  • Distinguish between smart Component (which handles state changes) and dump Component (which only uses state and doesn’t care about changes)
  • Do not have async calls in Component. Give them to Action Creator.
  • The Reducer logic should be as simple as possible and only copy and update data. The complicated business logic should be assigned to Action Creator.
  • The Reducer must return a new state object.
  • Action Creator and Reducer use pure functions
  • Try to have the Smart Component connect to the Store
  • Do not use Redux unless the application’s data management is complex and confusing.