Ali cloud recently doing activities, as low as 2 fold, interested can look at: promotion.aliyun.com/ntms/yunpar…


In order to ensure readability, this paper adopts free translation rather than literal translation.

React Advanced components

Higher-order functions take functions as arguments and return functions that are also functions. Similarly, the higher-order component (HOC for short) takes the React component as an argument and returns a new React component. A higher-order component is essentially a function, not a component. Higher-order components have the following functional form:

To read more quality articles pleaseJabber at the GitHub blog, a hundred quality articles a year waiting for you!

const EnhanceComponent = higherOrderComponent(WrappedComponent)
Copy the code
A simple example explains how higher-order components can be reused. You now have a component, MyComponent, that needs to fetch data from LocalStorage and render it to the interface. Import React, {Component} from'react'

class MyComponent extends Component {
  componentWillMount() {
    let data = localStorage.getItem('data');
    this.setState({data});
  }
  render() {
    return(
      <div>{this.state.data}</div>
    )
  }
}
Copy the code

The code is simple, but each component needs to rewrite the code in componentWillMount once when other components need the same data from LocalStorage to display, which is obviously redundant. Let me take a look at rewriting this part of the code using higher-order components.

import React, { Component } from 'react'

function withPersistentData(WrappedComponent) {
  return class extends Component {
    componentWillMount() {
      let data = localStorage.getItem('data');
      this.setState({data});
    }
    render() {// pass {... This.props} passes properties to the current component to the wrapped componentreturn<WrappedComponent data={this.state.data} {... this.props}/> } } } class MyComponent extends Component{render() {
    return <div>{this.props.data}</div>
  }
}

const MyComponentWithPersistentData = withPersistentData(MyComponent);
Copy the code

WithPersistentData is a higher-order component that returns a new component that handles the logic to fetch data from LocalStorage in a unified way. Then pass the data to the wrapped WrappedComponent through props. In the WrappedComponent, you can use this.props. Data to get the data to be displayed. Continue wrapping these components with the higher-level component withPersistentData.

Two, use scenarios

The application scenarios of higher-order components are as follows:

  1. Manipulation of the props
  2. Access component instances through ref
  3. Component status upgrade
  4. Wrap components with other elements

1. The manipulation of the props

Before the packaged component receives the props, the higher-order component can intercept the props, add, delete, or modify the props, and then pass the processed props to the packaged component, as in the example in 1.

2. Access the component instance through ref

The higher-level component ref gets a reference to the wrapped component instance, and then the higher-level component has the ability to directly manipulate the properties or methods of the wrapped component.

import React, { Component } from 'react'

function withRef(wrappedComponent) {
  return class extends Component{
    constructor(props) {
      super(props);
      this.someMethod = this.someMethod.bind(this);
    }

    someMethod() {
      this.wrappedInstance.comeMethodInWrappedComponent();
    }

    render() {// Add the ref attribute to the wrapped component to get the component instance and assign it to this.wrappedInstancereturn<wrappedComponent ref={(instance) => { this.wrappedInstance = instance }} {... this.props}/> } } }Copy the code

When the wrappedComponent is rendered, the ref callback is executed. The higher-order component holds the wrappedComponent instance reference through this.wrappedInstance. Call methods in wrappedComponent in someMethod with this.wrappedInstance. This usage is rarely used in real projects, but is useful when the reuse logic of higher-order component packaging requires collaborative support from the methods or properties of the wrapped component.

3. The component status is improved

High-order components can be stateless by elevating the state of the packaged component and the corresponding state processing method to the interior of the packaged component. A typical scenario is to use higher-order components to uniformly promote state that a controlled component needs to maintain itself.

import React, { Component } from 'react'

function withRef(wrappedComponent) {
  return class extends Component{
    constructor(props) {
      super(props);
      this.state = {
        value: ' '
      }
      this.handleValueChange = this.handleValueChange.bind(this);
    }

    handleValueChange(event) {
      this.this.setState({
        value: event.EventTarget.value
      })
    }

    renderConst newProps = {controlledProps: {value: this.state.value, onChange: {// newProps = {controlledProps: {value: this.state.value, onChange: this.handleValueChange } }return<wrappedComponent {... this.props} {... newProps}/> } } }Copy the code

This example promotes the state used by the value property of the controlled component and the callback function that handles value changes to the higher-order component. When we use the controlled component again, we can use it like this:

import React, { Component } from 'react'

function withControlledState(wrappedComponent) {
  return class extends Component{
    constructor(props) {
      super(props);
      this.state = {
        value: ' '
      }
      this.handleValueChange = this.handleValueChange.bind(this);
    }

    handleValueChange(event) {
      this.this.setState({
        value: event.EventTarget.value
      })
    }

    renderConst newProps = {controlledProps: {value: this.state.value, onChange: {// newProps = {controlledProps: {value: this.state.value, onChange: this.handleValueChange } }return<wrappedComponent {... this.props} {... newProps}/> } } } class SimpleControlledComponent extends React.Component {render() {/ / SimpleControlledComponent at this time for the stateless component, state by high order component maintenancereturn <input name="simple"{... this.props.controlledProps}/> } } const ComponentWithControlledState = withControlledState(SimpleControlledComponent);Copy the code

Parameter transfer

A higher-order component’s argument is not just one component; it can also accept other arguments. For example, to obtain data whose key is data from LocalStorage, if the key needed to obtain data is uncertain, the higher-order component withPersistentData will not meet the requirements. We can make it accept an extra parameter to determine which data to fetch from LocalStorage:

import React, { Component } from 'react'

function withPersistentData(WrappedComponent, key) {
  return class extends Component {
    componentWillMount() {
      let data = localStorage.getItem(key);
      this.setState({ data });
    }
    render() {// pass {... This.props} passes properties to the current component to the wrapped componentreturn<WrappedComponent data={this.state.data} {... this.props} /> } } } class MyComponent extends Component {render() {
    return <div>{this.props.data}</div>
  }
}
// 获取 key='data'The data of const MyComponent1WithPersistentData = withPersistentData (MyComponent,'data'); / / get the key ='name'The data of const MyComponent2WithPersistentData = withPersistentData (MyComponent,'name');

Copy the code

The new version of withPersistentData addresses the need to fetch different key values, but in practice we rarely use this way of passing parameters and instead use a more flexible and usable function form:

HOC(... params)(WrappedComponent)Copy the code

HOC(… The return value of params is a higher-order component that requires arguments that were passed into the HOC function first. Rewrite withPersistentData in this form as follows (note: higher-order components in this form are more succinct defined using arrow functions) :

import React, { Component } from 'react'

const withPersistentData = (key) => (WrappedComponent) => {
  return class extends Component {
    componentWillMount() {
      let data = localStorage.getItem(key);
      this.setState({ data });
    }
    render() {// pass {... This.props} passes properties to the current component to the wrapped componentreturn<WrappedComponent data={this.state.data} {... this.props} /> } } } class MyComponent extends Component {render() {
    return <div>{this.props.data}</div>
  }
}
// 获取 key='data'The data of const MyComponent1WithPersistentData = withPersistentData ('data')(MyComponent); / / get the key ='name'The data of const MyComponent2WithPersistentData = withPersistentData ('name')(MyComponent);


Copy the code

Four, inheritance to achieve higher-order components

All of the higher-order component implementations described above involve the higher-order component processing the general logic and then passing related properties to the wrapped component, which we call a property broker. In addition to property brokers, higher-order components can be implemented through inheritance: reuse of logic by inheriting wrapped components. Higher-order components implemented by inheritance are often used for render hijacking. For example, allow component rendering while the user is logged in, otherwise render an empty component. The code is as follows:

function withAuth(WrappedComponent) {
  return class extends WrappedComponent {
    render() {
      if (this.props.loggedIn) {
        return super.render();
      } else {
        returnnull; }}}}Copy the code

The WrappedComponent’s this.props. LoggedIn checks if the user is loggedIn, and if so, the WrappedComponent’s render method is called with super.render(). Otherwise, a NULL is returned. Implementing a higher-order component by inheritance is intrusive to the wrapped component, and when combining multiple higher-order uses, it is easy to lose logic because the subclass component forgets to call the parent component method through super. Therefore, when using high-order components, we should try to implement high-order components by proxy.

I refer to the React Way to Advance

communication

Dry goods series of articles summarized as follows, feel good point Star, welcome to add groups to learn from each other.

Github.com/qq449245884…

I am Xiaozhi, the author of the public account “Big Move the world”, and a lover of front-end technology. I will often share what I have learned to see, in the way of progress, mutual encouragement!

Pay attention to the public number, background welfare, you can see the welfare, you know.