Brief introduction: The separation of UI from business has been evolving, from early mixins, to HOC, to Render Prop. This article mainly compares HOC and talks about Render Props
1. Early mixins
Early reuse businesses were implemented through mixins, such as component A and component B, which had common functions that were stripped off and combined into a common collection that was then passed to each component call.
//Common Function Part
const someMixins={
printColor(){
console.log(this.state.color);
}
printWeight(){
console.log(this.state.weight);
}
}
class Apple extends React.Component{
//For demonstration purposes only, mixins are generally created through React.createClass, and ES6 does not have the key:value notation
mixins:[someMixins]
constructor(props){
super(props);
this.state={
color:'red',
weight:'100g'
}
this.printColor=this.printColor.bind(this);
}
render(){
return <div className="m-box" onClick={this.printColor}>
//This is an apple
</div>
}
}
class Banana extends React.Component{
mixins:[someMixins]
constructor(props){
super(props);
this.state={
color:'yellow',
weight:'200g'
}
this.printColor=this.printColor.bind(this);
}
render(){
return <div className="m-box" onClick={this.printColor}>
//This is a banana
</div>
}
}
In the example above, both Apple and Banana have printColor and printWeight methods to separate public services through mixins.Mixeins have been removed in React16.0, and are only described here.
2 . HOC
HOC simply understands that a component factory accepts the original component as a parameter, adds functionality and business, and returns to the new component.Here are a few examples of HOC parameters.
(1) Parameters are only original components, such as:
const redApple = withFruit(Apple);
(2) Parameters are the original component and an object, such as:
const redApple = withFruit(Appleļ¼{color:'red',weight:'200g'});
However, this is less common. If only attributes are passed in the object, the value can actually be passed through the props of the components. The main purpose of HOC is to separate business, display the UI, and the attributes and states in some components, we usually specify them through props.
(3) Parameters are the original component and a function, such as:
const redApp=withFruit(App,()=>{console.log('I am a fruit')})
This is a typical example of HOC, where the original component parameters represent the UI part, and the function parameters represent the processing logic to generate new components after coupling in the HOC factory.
(4) Curitization
The most common is to take only one original component as a parameter, but encapsulate business logic on the outside, such as in the conect function of react-redux:
class Admin extends React.Component{
}
const mapStateToProps=(state)=>{
return {
};
}
const mapDispatchToProps=(dispatch)=>{
return {
}
}
const connect(mapStateToProps,mapDispatchToProps)(Admin)
This is not a strict coritization, but the idea is the same: in the factory functions of HOC, a parent function is packaged to specify business logic.
3. Disadvantages of HOC
Let's look at the shortcomings of HOC:
(1) The source is difficult to trace and there is an attribute coverage problem
If the original component A passes through factory function 1, factory function 2, and factory function 3...Construct, and finally generate Component B. We know that Component B has many props different from Component A, but we just pass Component B and we don't know which Component comes from which Factory Function.At the same time, if two factory functions modify a property of the same name at the same time, there will be a problem of property override, which will invalidate the result of the previous factory function modification.
(2) HOC is statically constructed
Static build means that a new component is generated and not rendered immediately. A HOC component factory is a component that is built statically, similar to redeclaring a component's parts.In other words, the declared periodic function inside the HOC factory function will only be executed if the new component is rendered.
(3) Will result in useless empty components
3 . render props
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}>
{/*
Instead of providing a static representation of what <Mouse> renders,
use the `render` prop to dynamically determine what to render.
*/}
{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>
);
}
}
The above is an example given by the official website, the main part of which is the following two sentences:
Class Mouse extends React.component{
...
{this.props.render(this.state)}
...
}
......
<Mouse render={mouse => (
<Cat mouse={mouse} />
)}/>
When using a Mouse component, an available component Cat is passed to the parent component Mouse through a render property, whereas in a Mouse component, its own state object can be passed to the Cat component, and the value of the mouse property in a Cat component is the same as that in a Mouse parent component.
To simplify, a parent component can pass its own state to a child component, which can render based on the parent component's state object.
The benefits of this are:
(1) Don't worry about naming props
(2) Traceable, the props of child components must be from direct parent components
(3) It is built dynamically.