What is React HOC?
React HOC - Higher Order Component, also known as react's high-order Component, is usually implemented by a function that accepts one Component and outputs another, similar to Java's proxy mode. It implements some object decorators or interceptors in combination or other ways.
To sum up, React HOC is essentially a function. This function receives a component old and then returns a new component new for your use. This new component is built on the basis of the old component. Therefore, some extensions are implemented on the functions of the old component, but this extension does not invade the code of the old component at all.
The name of the React HOC high-order component actually comes from the high-order function in JS. In JavaScript, those functions that can receive another function as a parameter are called high-order functions, such as common reduce functions, map functions, etc. Therefore, in React, functions that receive a component as a parameter and return a new component are called high-order components. The common forms are as follows:
//High order component definition const HOC = (WrappedComponent) => class WrapperComponent extends Component { render() { return <WrappedComponent {...this.props} />; } }
Function and implementation of React HOC
The functions of React HOC are as follows:
- Code reuse (obviously) and logical abstraction
- Abstract and operate on state and props
- Render hijacking
- Refine the wrapped component, such as adding a lifecycle
There are usually two ways to implement React HOC: attribute proxy and reverse inheritance.
The core of React HOC - closure principle
First look at a summation function add. The function is very simple. Enter a number a and return a+2. Generally, the summation function is defined as follows:
function add(num){ var num1 = 2; return num+num1; } console.log(add(1));//3
However, what if we don't need to sum immediately, but recalculate as needed in the later code? Instead of returning the result of summation, you can return the function of summation.
function lazy_add(num) { var num1 = 2; var add = function () { return num1 +num; } return add; } var fn = lazy_add(1); console.log(fn());//3
When we call lazy_ When you add(), the result returned is not the summation result, but the summation function:
var fn = lazy_add(1);
When the function fn is called, the summation result is really calculated:
fn();//3
In this example, we are in the function lazy_ The function add is defined in add, and the internal function add can refer to the external function lazy_add parameters and local variables, when lazy_ When add returns the function add, the relevant parameters and variables are saved in the returned function, but the external operation is impossible. This program structure called "Closure" has great power.
Explain closures from the memory model of JS
Calling lazy_ When add (1), the local variables num and num1 are saved in the local variable table of the method stack. When the method is executed and out of the stack, because the returned sum method also references num and num1, JS will save num and num1 to the heap for storage, and only the sum method has references to these two variables, which cannot be referenced elsewhere, This is actually consistent with the Java virtual machine model, which is the core of closures.
Implementation of attribute agent for React HOC
The essence of the attribute proxy method is composition. In the implementation method, it is to define a function that receives a component old and creates a new component new in the function as a return. Based on the principle of closure, the new component can use the old component as an attribute and reprocess and construct a new component on the old component, For Example, some attribute inputs can be forcibly added to the old component. For Example, the following program can add a value attribute and Onchange event input to the strong behavior input tag based on the Example component, but it is not necessary to modify the original old component. The code is as follows:
Original component Example:
class Example extends React.Component { render() { //{... Props} actually means to put only the key value pairs in props into the new {} return <input name="name" {...this.props}/> } }
Higher order component function ppHOC:
function ppHOC(WrappedComponent) { return class PP extends React.Component { constructor(props) { super(props); this.state = { text: 'Initial value' }; this.onNameChange = this.onNameChange.bind(this); } onNameChange(event) { this.setState({ text: event.target.value }) } render() { const newProps = { value: this.state.text, onChange: this.onNameChange } //{... Props} actually means to put only the key value pairs in props into the new {} return <WrappedComponent {...this.props} {...newProps}/>; } } }
Get the higher-order component PExample and render:
const PExample = ppHOC(Example); ReactDOM.render( <PExample />, document.getElementById('root') );
**Effect achieved:
Reverse inheritance implementation of React HOC
The difference between the HOC implementation of reverse inheritance and the implementation of attribute proxy is that the new component of attribute proxy operates the old component as its own attribute, while in reverse inheritance, the new component inherits the old component, so as to change the component internally. For example, you can directly modify the render function of the old component to realize rendering interception and other operations. The implementation code is as follows:
Higher order component functions:
function iiHOC(WrappedComponent) { return class Enhancer extends WrappedComponent { render() { const elementsTree = super.render(); let newProps = {}; if (elementsTree && elementsTree.type === 'input') { newProps = {value: 'find input label!'}; } const props = Object.assign({}, elementsTree.props, newProps);//Add a new value attribute const newElementsTree = React.cloneElement(elementsTree, props, elementsTree.props.children) return newElementsTree; } } }
Get the higher-order component IExample and render:
const IExample = iiHOC(Example); ReactDOM.render( <IExample />, document.getElementById('root') );
**Effect achieved: