React is great for building large applications because of its high-order components and reverse component inheritance, in addition to its flexible JSX syntax. As we build large applications, higher-order components and reverse inheritance make many business scenarios very efficient to implement. In the development, we will certainly repackage the UI component library to meet the requirements of the design of components for everyone to call; In addition, there will also be UI component library migration in the development process. The component name and API name of the two libraries are inconsistent, which requires us to rewrite the component name and API name. Business scenario is one of the most important, of course, our project completion degree is high, there are many nodes called a complex components, the need to in some on the basis of its development and rewritten, but carries the risk of social phenomena, at this time our high order component and reverse inheritance is played a huge role.

High order component

React a high-order component is a function that takes a component and returns a new component. We implemented decorator patterns (see decorators in ES7) with higher-order components (property proxy patterns) in our building application.

Business 1: Secondary encapsulation of components

Antd component library is rewritten to make its component library style meet the design requirements. Index. Js calls

import MyButton from 'myButton.js'
import MyTree from 'myTree.js'
export {
    MyButton,
    MyTree
}
Copy the code

We wrapped ANTD’s Button into our own MyButton style style. Colors is similar to type in ANTD and features primary, Danger, and other colors. Button with colors as Danger.

import 'myButton.less'
export default class MyButton extends Component {
    render() {
        let{ onClick, colors, className, ... others } = this.propsreturn (
            <Button 
                className=`${className} my-button-wrap button-${colors}` onClick={(e) => { onClick(e) } {... others} > </Button> ) } }Copy the code

Mybutton.less part implementation

.button-danger {
    background-color: #e14c46;
    color: #fff;
    &:hover {
	  background-color: #d7332c;
	  color:#fff;
    }
    &:disabled {
      background-color: #F19B96;
      color: #F2F2F2 ;
      &:hover {
        color: #F2F2F2 ;
        background-color: #fdcac6;}}}Copy the code

Business 2: Project migration of components

In our project, we encountered the problem of having different API names when migrating the framework. We rewrote the TREE control API in ANTD into the API in our previous project. So for example, let’s rewrite onExpand to myExpand. Of course, we can add more complex functionality, depending on our business needs. This is just a demo, so keep it simple.

const { TreeNode } = Tree;
export default class MyTree extends Component {
    render() {
        let{ myClick, myExpand, ... others } = this.propsreturn( <Tree onCheck={() => { myCheck() } onExpand = {(expandedKeys, {expanded: bool, node}) => { myExpand(expandedKeys, {expanded: bool, node}) } {... others} > </Tree> ) } } MyTree.myTreeNode = TreeNodeCopy the code

Business 3: Decorate the previous components

Of course, sometimes we can write a business, and we can just add a little bit of decoration on top of the previous component, and we can save a lot of code by using decorators. This is where higher-order components play an important role. (Decorator Decorator is an experimental JavaScript proposal.)

import OldComponent from "./Component.js"
const newComponent = (WrapComponent) => {
    
    return class extends WrapComponent {
        render() {
            let props = this.props
            letnewProps = { click:() => {}, ... this.props }return <WrapComponent />
        }
    }
}
export default newComponent(OldComponent)
Copy the code

Business four: Factory pattern implementation

Before obtaining the requirements of the program, the same part of the implementation method is extracted and written into the internal higher-order function. The function then returns similar but completely different components, taking different components and functions as arguments.

function hocFn({
    WrappedComponent, 
    data, 
    callback = () => console.log('No callback function passed in'}) {//... And returns another component...return class extends React.Component {
    constructor(props) {
      super(props);
      this.handleChange = this.handleChange.bind(this);
      this.state = {
        data: data
      };
    }

    componentDidMount() {
      callback()
    }

    render() {
      return<WrappedComponent data={this.state.data} {... this.props} />; }}; } // create different tables ()let TreeTable = hocFn(Tree, data1, () => console.log('Create a tree table'))
let EditTable = hocFn(Form, data1, () => console.log('Create an editable table'))
Copy the code

Reverse inheritance of higher-order components

The two core functions of reverse inheritance, one is rendering hijacking and the other is manipulating state bar. There are two ways to write reverse inheritance, and the two ways have different capabilities.

Implements a child component componentChild.js

export default class ComponentChild extends Component {
  constructor(props) {
    super(props)
    this.state = {
      num: 2019
    }
  }
  componentDidMount() {
    console.log("child component Did Mount")}clickComponent() {
    console.log("Component click")}render() {
    return (
      <div>{this.state.num}</div>
    )
  }
}
Copy the code

Decorative components are passed in directly

imoprt ComponentChild from './ComponentChild.js'
let iihoc = WrapComponet => class extends WrapComponet {
    constructor(props) {
        super(props)
        this.state = {
            num: 2000
        }
    }
    componentDidMount() {
        console.log('iihoc componentDidMount')
        this.clickComponent()
    }
    render() {return(<div>< div onClick={this.clickComponent}>iiHoc click </div> <div>< /div> </div>})}export default iihoc(ComponentChild)
Copy the code

The advantage of this approach over property brokering is that the external component can call the inherited component’s methods. You cannot override inherited states and hooks.

Call the super. Render ()

imoprt ComponentChild from './ComponentChild.js'
let iihoc = WrapComponet => class extends WrapComponet {
    constructor(props) {
	    super(props)
	    this.state = {
            num: 2000
	    }
    }
    componentDidMount() {
        console.log('iihoc componentDidMount')
        this.clickComponent()
    }
    render() {return<div> <div onClick={this.clickComponent}>iiHoc click </div> <div>{super.render()}</div> </div>)}}export default iihoc(ComponentChild)
Copy the code

In this way, the state of the external component can completely override the state and hook functions of the inherited component. External components can also call methods of inherited components.

render() {
    let renderchild = super.render();
    letnewProps = { ... renderTree.props, onClick: this.handleClick }; const newRenderchild = React.cloneElement( renderchild, newProps );return newRenderchild;
}
Copy the code

Solve nested hell (HOOK)

Components made up of higher-order components, render props, and other abstractions form “nested hell.” Hooks in Reload 16.8 are a solution to nested hell.