React High-level component HOC

😊 article is slightly longer, do a good heart preparation oh, recommended reading 15 minutes.

define

  • HOC is actually a function that takes a component as an argument and returns a wrapper component as a return value
  • The same functionality is required in multiple different components
  • Higher-order components and decorators are one pattern, so higher-order components can be used as decorators

role

  • It doesn’t require ES6 or other features that need to be compiled. Where there are functions, there is HOC.
  • Debug is friendly and can be displayed by the React component tree, so it’s clear how many layers there are and what each layer is doing.

Added notes for decorators

A Decorator (@) is used in many of the following cases. A Decorator is a function that modifies the behavior of a class.

More usage may refer to Jane books an article: www.jianshu.com/p/275bf41f4…

Basic form

const EnhancedComponent = higherOrderComponent(WrappedComponent)

function hoc(WrappedComponent) {
    return class HOC extends React.Component {
        componentDidMount() {
            console.log("hoc");
        }

        render() {
            return<WrappedComponent />}}} class extends React.Component {render() {
        return <div></div>
    }
}

exportdefault hoc(ComponentClass); // Use @hoc as a decoratorexport default class ComponentClass extends React.Component {
    //...
}
Copy the code

Common use

  • Props Proxy: High-level components perform operations on Props of ComponentClass
  • Inheritance Inversion: Higher-order components inherit from ComponentClass

Common functions of the properties Proxy

  1. Operation props: You can add, delete, modify, or check the props of the original component without damaging the original component
// Add new propsfunction ppHOC(WrappedComponent) {
  return class PP extends React.Component {
    render() {
      const newProps = {
        user: currentLoggedInUser
      }
      return<WrappedComponent {... this.props} {... newProps}/> } } }Copy the code
  1. Component instances are accessed through refs to invoke component-related methods
// WrappedComponent calls the ref callback during its initial rendering, passing in the component instance and invoking the component method in the proc methodfunction refsHOC(WrappedComponent) {
  return class RefsHOC extends React.Component {
    proc(wrappedComponentInstance) {
      wrappedComponentInstance.method()
    }

    render() { // Object.asign(); Copy the values of all enumerable properties from one or more source objects to the target Object const props = object.assign ({}, this.props, {ref: this.proc.bind(this)})return<WrappedComponent {... props}/> } } }Copy the code
  1. Extract state, which can be extracted by passing props and callback functions
// Extract the input value and onChange methodsfunction ppHOC(WrappedComponent) {
  return class PP extends React.Component {
    state = {
        name: ' '
    }
    
    onNameChange(event) {
      this.setState({
        name: event.target.value
      })
    }
    
    render() {
      const newProps = {
        name: {
          value: this.state.name,
          onChange: this.onNameChange.bind(this)
        }
      }
       return<WrappedComponent {... this.props} {... @pphoc class Example extends React.Component {newProps}/>}}/ /render() {// After using the ppHOC decorator, the component props has the name attribute added and the input becomes the controlled componentreturn <input name="name"{... this.props.name}/> } }Copy the code
  1. Wrap WrappedComponent with other elements for layout, styling, and more
function ppHOC(WrappedComponent) {
  return class PP extends React.Component {
    render() {
      return (
        <div style={{display: 'block'}}> <WrappedComponent {... this.props}/> </div> ) } } }Copy the code

Inheritance Inversion

  1. HOC controls the render output of the WrappedComponent and can hijack the render content inherited from the class, modify it, filter it, and return the new display
// Filter out ul elements in the original componentfunction hoc(ComponentClass) {
    return class HOC extends ComponentClass {
        render() { const elementTree = super.render(); elementTree.props.children = elementTree.props.children.filter((z) => z.type ! = ="ul")
            
            return React.cloneElement(elementTree);
        }
    }
}

@hoc
export default class ComponentClass extends React.Component {
    render() {
        return (
            <div>
                <p style={{color: 'brown'}} >!!! < / p > < ul > < li > 1 < / li > < li > 2 < / li > < / ul > < / div >)}}Copy the code
  1. To manipulate state,HOC can manipulate the state of a WrappedComponent instance. But this breaks the state of the WrappedComponent, so to restrict HOC reading or adding state, add state in a separate namespace
export function IIHOC(WrappedComponent) {
  return class II extends WrappedComponent {
    render() {
      return (
        <div>
          <p>Props</p> <pre>{JSON.stringify(this.props, null, 2)}</pre>
          
          <p>State</p><pre>{JSON.stringify(this.state, null, 2)}</pre>
          
          {
            super.render()
          }
        </div>
      )
    }
  }
}
Copy the code
  1. Conditions apply colours to a drawing
// Assuming this.props. LoggedIn is true, HOC will render the WrappedComponent completelyfunction iiHOC(WrappedComponent) {
  return class ii extends WrappedComponent {
    render() {
      if (this.props.loggedIn) {
        return super.render()
      } else {
        return null
      }
    }
  }
}
Copy the code
  1. Resolve missing WrappedComponent names
// Components wrapped in HOC lose their original names, affecting development and debugging, Can be as HOC in WrappedComponent name prefix name const. The componentName = WrappedComponent displayName | | WrappedComponent. Name | |'Component';

static displayName = `withModal(${componentName}) `;Copy the code

The practical application

  1. Record the localStorage return value
Const withStorage = (key) => WrappedComponent => {const withStorage = (key) => WrappedComponent => {return class extends Component {
    componentWillMount() {
        let data = localStorage.getItem(key);
        this.setState({data});
    }
    render() {
      return<WrappedComponent data={this.state.data} {... this.props} /> } } } @withStorage('data')
class MyComponent2 extends Component {  
    render() {
        return <div>{this.props.data}</div>
    }
}

@withStorage('name')
class MyComponent3 extends Component {  
    render() {
        return <div>{this.props.data}</div>
    }
}
Copy the code
  1. In the project, re-open the Modal box every time and destroy the data in Modal every time to prevent data contamination
const modalHoc = (options) => WrappedComponent => {
    const componentName = WrappedComponent.displayName || WrappedComponent.name || 'Component';

    return class ModalComponent extends Component {
        static displayName = `withModal(${componentName}) `;render() {
            const {visible, onCancel} = this.props;

            let title;
            if (typeof options === 'string') title = options;

            if (typeof options === 'function') title = options;

            if (typeof options === 'object') title = options.title;

            if (typeof title === 'function') title = title(this.props);

            return (
                <Modal
                    destroyOnClose
                    width="60%"
                    bodyStyle={{padding: 0}}
                    footer={null}

                    {...options}
                    title={title}

                    onCancel={onCancel}
                    visible={visible}
                >
                    <WrappedComponent {...this.props}/>
                </Modal>
            );
        }
    }
};

@modalHoc('You can pass in different types of headings.')
Copy the code

😊 reference links: the react. HTML. Cn/docs/who…

😊 just joined the nuggets community, welcome to put forward valuable suggestions, progress together!