React In-depth series provides in-depth explanations of key concepts, features, and patterns in React to help you understand React and use React flexibly in your projects.

This is the last installment of the React in-depth series. We will introduce some of the most common patterns used when developing React applications. Not all of these patterns have official names, so the naming of some of these patterns is not necessarily accurate.

1. Controlled components

The React component’s data flow is driven by state and props, but for form elements such as input, Textarea, and SELECT, it breaks the inherent data flow in React because it accepts user input directly on the interface. React addresses this issue by introducing controlled components. Controlled components refer to the values displayed by form elements such as input, which are still retrieved by the component’s state, rather than directly displaying user input on the interface.

Implementation of controlled components: Change the component state by listening for changes in form element values, and display the value that the component will eventually display based on state. A simple example is as follows:

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: ' '};

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('A name was submitted: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input type="text" value={this.state.value} onChange={this.handleChange} />
        </label>
        <input type="submit" value="Submit"/> </form> ); }}Copy the code

The equivalent concept of a controlled component is an uncontrolled component, which fetches the value of a form element through a REF and has a unique role in some scenarios (such as setting the focus of a form element).

2. Container components

Container components and presentation components are a set of corresponding concepts that focus on the separation of component logic from component presentation. The logic is taken care of by the container component, and the presentation component focuses on the presentation of the view layer. Container components and presentation components are covered in detail in React In-depth Series 2: Component Categories and won’t be covered here.

3. Advanced components

A higher-order component is a special function that takes a component as input and outputs a new component. The main function of higher-order components is to encapsulate the general logic of components and realize logic reuse. High-order components were covered in detail in React In-depth Series 6: High-order Components and won’t be covered here.

4. The Children

First, the schema may not be properly named. In this mode, the Children property of the React component is used to decouple components. Commonly used in a framework where a component is responsible for the UI and components within the framework can be flexibly replaced.

An example:

// ModalDialog.js
export default function ModalDialog({ children }) {
  return <div className="modal-dialog">{ children }</div>;
};

// App.js
render() {
  <ModalDialog>
    <SomeContentComp/>
  </ModalDialog>
}
Copy the code

The ModalDialog component is a box of the UI that can be flexibly replaced.

5. Render Props

Render Props encapsulates the rendering logic of a component into a function, receives this function with the component Props, and then calls this function inside the component to execute the encapsulated rendering logic.

Look at an official example:

class Cat extends React.Component {
  render() {
    const mouse = this.props.mouse;
    return (
      <img src="/cat.jpg" style={{ position: 'absolute', left: mouse.x, top: mouse.y }} />
    );
  }
}

class Mouse extends React.Component {
  constructor(props) {
    super(props);
    this.handleMouseMove = this.handleMouseMove.bind(this);
    this.state = { x: 0, y: 0 };
  }

  handleMouseMove(event) {
    this.setState({
      x: event.clientX,
      y: event.clientY
    });
  }

  render() {
    return (
      <div style={{ height: '100%'}} onMouseMove={this.handleMouseMove}> {/* * Mouse does not know how to render this part of the Mouse, } {this.props. Render (this.state)} </div>); } } class MouseTracker extends React.Component {render() {
    return (
      <div>
        <h1>Move the mouse around!</h1>
        <Mouse render={mouse => (
          <Cat mouse={mouse} />
        )}/>
      </div>
    );
  }
}

Copy the code

The Mouse listens for Mouse movements and saves the Mouse position in State. But the Mouse component doesn’t know what it’s going to render, so it needs to call the this.props. Render method to perform the render logic. In this case, the Cat component renders to where the mouse moves, but it’s perfectly possible to use other effects to follow the mouse movement by simply changing the Render method. Thus, the Mouse component only cares about the Mouse position movement, and the interface effect that follows the Mouse movement is determined by the component that uses the Mouse. This is an idea based on faceted programming (familiar to those of you who know back-end development).

With this pattern, it is customary to assign the function that encapsulates the rendering logic to a component property named Render (as in this example), but this is not required; you can use other property names as well.

A variant of this pattern is passed directly using the Children property that comes with the React component. Rewrite the above example as:

Class Mouse extends React.Component {// omitrender() {
    return (
      <div style={{ height: '100%'}} onMouseMove={this.handleMouseMove}> {/* * Mouse does not know how to render this part of the Mouse, */} {this.props. Children (this.state)} </div>); } } Mouse.propTypes = { children: PropTypes.func.isRequired }; class MouseTracker extends React.Component {render() {
    return (
      <div>
        <h1>Move the mouse around!</h1>
        <Mouse>
          {mouse => (
            <Cat mouse={mouse} />
          )}
        </Mouse>
      </div>
    );
  }
}
Copy the code

Notice how children are assigned.

The React Router and React-Motion libraries both use the Render Props mode. ** In many scenarios, the functions implemented by Render Props can also be implemented by higher-order components. ** This example can also be implemented with higher-order components, please think for yourself.

6. The Provider component

The React context is used to store data that components need to use in the context and provide a higher-order component to fetch data from the context.

An example:

Create MyProvider and store the shared data in its context. MyProvider is usually used as the topmost component to ensure that other components can access the data in context:

import React from "react";
import PropTypes from "prop-types";

const contextTypes = {
  sharedData: PropTypes.shape({
    a: PropTypes.bool,
    b: PropTypes.string,
    c: PropTypes.object
  })
};

export class MyProvider extends React.Component {

  static childContextTypes = contextTypes;

  getChildContext() {// Assume that the data in the context is fetched from propsreturn { sharedData: this.props.sharedData };
  }

  render() {
    returnthis.props.children; }}Copy the code

Then create a higher-order component, connectData, that fetches the required data from the context:

export const connectData = WrappedComponent =>
  class extends React.Component {
    static contextTypes = contextTypes;

    render() {
      const { props, context } = this;
      return<WrappedComponent {... props} {... context.sharedData} />; }};Copy the code

Finally used in the application:

const SomeComponentWithData = connectData(SomeComponent)

const sharedData = {
    a: true,
    b: "react",
    c: {}
};

class App extends Component {
  render() {
    return( <MyProvider sharedData={sharedData}> <SomeComponentWithData /> </MyProvider> ); }}Copy the code

The Provider component mode is very useful. It is used in libraries such as React-Redux and Mobx-React.

React This is the end of the in-depth series of articles on React. We hope to help you understand React better and become more proficient in using React.


My new book, The React Road, is out now. If you’re interested in React, check it out. Purchase address: Dangdang JINGdong


Welcome to pay attention to my public number: the big front end of the old cadre