When any project develops to a certain complexity, it will inevitably face the problem of logic reuse. stayReact
There are usually the following ways to realize logical reuse in:Mixin
、High order component (HOC)
、Decorator
、Render Props
、Hook
。 This article mainly analyzes the advantages and disadvantages of the above methods to help developers make more suitable methods for business scenarios.
Mixin
This may be just fromVue
to turn toReact
The first method that developers can think of.Mixin
It has been widely used in various object-oriented languages,Its function is to create an effect similar to multiple inheritance for single inheritance languages。 Although nowReact
It has been abandoned, butMixin
It wasReact
A design pattern for code sharing.
The generalized mixin method is to mount the methods in the mixin object to the original object by means of assignment to realize the mixing of objects, similar to the function of object.assign() in ES6. The principle is as follows:
const mixin = function (obj, mixins) {
const newObj = obj
newObj.prototype = Object.create(obj.prototype)
for (let prop in mixins) {
//Traverse the properties of mixins
if (mixins.hasOwnPrototype(prop)) {
//Determine whether it is the self attribute of mixin
newObj. prototype[prop] = mixins[prop]; // assignment
}
}
return newObj
};
Using mixin in react
Suppose that in our project, multiple components need to set the defaultname
Properties, usingmixin
So that we don’t have to write multiple identical ones in different componentsgetDefaultProps
Method, we can define amixin
:
const DefaultNameMixin = {
getDefaultProps: function () {
return {
name: "Joy"
}
}
}
In order to usemixin
, which needs to be added in the componentmixins
Attribute, and then write usmixin
Wrap it into an array asmixins
Attribute value of:
const ComponentOne = React.createClass({
mixins: [DefaultNameMixin]
render: function () {
return Hello {this.props.name}
}
})
Writtenmixin
It can be reused in other components.
becausemixins
The attribute value is an array, which means that weMultiple calls can be made in the same componentmixin
。 In the above example, a slight change is made to get:
const DefaultFriendMixin = {
getDefaultProps: function () {
return {
friend: "Yummy"
}
}
}
const ComponentOne = React.createClass({
mixins: [DefaultNameMixin, DefaultFriendMixin]
render: function () {
return (
Hello {this.props.name}
This is my friend {this.props.friend}
)
}
})
We can even be in amixin
Contains othersmixin
。
For example, write a new onemixin``DefaultProps
Including the aboveDefaultNameMixin
andDefaultFriendMixin
:
const DefaultPropsMixin = {
mixins: [DefaultNameMixin, DefaultFriendMixin]
}
const ComponentOne = React.createClass({
mixins: [DefaultPropsMixin]
render: function () {
return (
Hello {this.props.name}
This is my friend {this.props.friend}
)
}
})
So far, we can conclude thatmixin
At least have the following advantages:
- The same can be used in multiple components
mixin
; - Multiple can be used in the same component
mixin
; - Can be in the same
mixin
Nested multiplemixin
;
However, in different scenarios, advantages may also become disadvantages:
- Destroying the encapsulation of the original components may require maintenance of new ones
state
andprops
Equal state; - Different
mixin
The name in is unknowable, which is very easy to conflict; - Recursive call may occur, which increases the complexity of the project and the difficulty of maintenance;
besides,mixin
It has its own processing logic for state conflicts, method conflicts, and the call sequence of multiple lifecycle methods. Interested students can refer to the following articles:
High order components
becausemixin
There are the above defects, soReact
Strippedmixin
, use insteadHigh order components
To replace it.
High order components
It is essentially a function, which takes a component as a parameter and returns a new component。
React
The official also uses it when implementing some public componentsHigh order components
, such asreact-router
MediumwithRouter
, andRedux
Mediumconnect
。 Here withwithRouter
As an example.
By default, it must be throughRoute
Only components with route matching rendering existthis.props
, to ownRouting parameters
, can be usedFunctional navigation
Implementation of the writing method ofthis.props.history.push('/next')
Jump to the page of the corresponding route.High order components
MediumwithRouter
The function is to make aRoute
Components for routing packages, packages toRoute
Inside, so thatreact-router
Three objects ofhistory
、location
、match
Put into theprops
Attribute, so it can be implementedFunctional navigation jump
。
withRouter
Implementation principle of:
const withRouter = (Component) => {
const displayName = `withRouter(${Component.displayName || Component.name})`
const C = props => {
const { wrappedComponentRef, ...remainingProps } = props
return (
{context => {
invariant(
context,
`You should not use outside a `
);
return (
)
}}
)
}
Use code:
import React, { Component } from "react"
import { withRouter } from "react-router"
class TopHeader extends Component {
render() {
return (
navigation bar
{/ * click jump login * /}
sign out
)
}
exit = () => {
//After wrapping withrouter higher-order functions, you can use this.props to jump
this.props.history.push("/login")
}
}
//Use withrouter to package components and return history, location, etc
export default withRouter(TopHeader)
becauseHigh order components
The essence of isMethod to get the component and return the new component
So in theory, it can also be likemixin
Also realize multiple nesting.
For example:
Write a higher-order function that enables singing
import React, { Component } from 'react'
const widthSinging = WrappedComponent => {
return class HOC extends Component {
constructor () {
super(...arguments)
this.singing = this.singing.bind(this)
}
singing = () => {
console.log('i am singing!')
}
render() {
return
}
}
}
Write a higher-order function that enables dancing
import React, { Component } from 'react'
const widthDancing = WrappedComponent => {
return class HOC extends Component {
constructor () {
super(...arguments)
this.dancing = this.dancing.bind(this)
}
dancing = () => {
console.log('i am dancing!')
}
render() {
return
}
}
}
Use the above high-order components
import React, { Component } from "react"
import { widthSing, widthDancing } from "hocs"
class Joy extends Component {
render() {
return Joy
}
}
//Give joy the ability to sing and dance
export default widthSinging(withDancing(Joy))
It can be seen from the above that by simply wrapping with high-order functions, you can turn the original simple joy into a nightclub prince who can both sing and dance!
Conventions for using hoc
in useHOC
At the time of, there were some conventional agreements:
- Pass irrelevant props to the packaging component (pass props irrelevant to its specific content);
- Step by step combination (avoid different forms of HOC serial calls);
- Include the displayName of the display for debugging (each hoc should comply with the display name of the rule);
- Don’t be
render
Use high-order components in the function (each render, the high-order will return new components, which will affect the diff performance); - Static methods must be copied (new components returned through high-order will not contain static methods of the original components);
- Avoid using ref (Ref will not be passed);
Advantages and disadvantages of hoc
So far, we can summarizeHigh order component (HOC)
Advantages:
HOC
Is a pure function, easy to use and maintain;- Also due to
HOC
Is a pure function, which supports the introduction of multiple parameters to enhance its scope of application; HOC
What is returned is a component, which can be combined and nested, with strong flexibility;
of courseHOC
There will also be some problems:
- When multiple
HOC
When nested, you cannot directly judge theprops
From whichHOC
Responsible for delivery; - When a parent-child component has the same name
props
, which will cause the parent component to cover the component with the same nameprops
Andreact
No error will be reported, and the developer’s perception is low; - every last
HOC
All return a new component, resulting in a lot of useless components. At the same time, it deepens the component level, which is not convenient for troubleshooting problems;
Decorator
andHigh order components
It belongs to the same model and will not be discussed here.
Render Props
Render Props
It is a very flexible and highly reusable mode, which can encapsulate specific behaviors or functions into a component and provide it to other components for use, so that other components have such capabilities。
The term “render prop” refers to a technique for sharing code between React components using a prop whose value is a function.
This isReact
Official forRender Props
The definition of is translated into vernacular, namely:“Render Props
Is to achieveReact Components
A technology of code sharing between componentsprops
It contains afunction
Type, which can be called by the componentprops
Property to implement the internal rendering logic of the component “.
Official example:
Hello {data.target}} />
As above,DataProvider
The component has arender
(or other names)props
Property, which is a function, and this function returns aReact Element
, this function is called inside the component to complete rendering, so this component is usedrender props
Technology.
Readers may wonder, “why do we need to callprops
Property to achieve internal rendering of components, rather than directly rendering within components “? borrowReact
Official reply,render props
Not everyReact
The skills that developers need to master, and even you may never use this method, but its existence does provide developers with an alternative when thinking about component code sharing.
Render Props
Usage scenarios
We may need to use pop-up frequently in project development. The pop-up UI can be changeable, but its function is similar, that isopen
andclose
。 withantd
For example:
import { Modal, Button } from "antd"
class App extends React.Component {
state = { visible: false }
//Control pop-up display and hiding
toggleModal = (visible) => {
this.setState({ visible })
};
handleOk = (e) => {
//Do something
this.setState({ visible: false })
}
render() {
const { visible } = this.state
return (
Open
Some contents...
)
}
}
The above is the simplestModel
We still need to pay attention to its display state and realize its switching method even if it is simple to use. But developers only want to pay attention to those related to business logiconOk
, the ideal way to use it should be as follows:
Open
Some contents...
Can passrender props
Achieve the above usage:
import { Modal, Button } from "antd"
class MyModal extends React.Component {
state = { on: false }
toggle = () => {
this.setState({
on: !this.state.on
})
}
renderButton = (props) =>
renderModal = ({ onOK, ...rest }) => (
{
onOK && onOK()
this.toggle()
}}
onCancel={this.toggle}
/>
)
render() {
return this.props.children({
Button: this.renderButton,
Modal: this.renderModal
})
}
}
In this way, we have completed a system with state and basic functionsModal
, we use this on other pagesModal
You only need to pay attention to specific business logic.
As can be seen from the above,render props
Is a realReact
Components, not likeHOC
Same, just oneFunctions that can return components, which also means usingrender props
Not likeHOC
There is no need to worry about the nesting of component levelsprops
Coverage problems caused by naming conflicts.
render props
Use restrictions
stayrender props
Should be avoided inArrow function
, because this will have a performance impact.
For example:
//Bad example
class MouseTracker extends React.Component {
render() {
return (
(
)}/>
)
}
}
It’s not good to write like this, becauserender
The method is possible to render multiple times, usingArrow function
, which will cause each rendering to pass inrender
The values of will be different, but in fact there is no difference, which will lead to performance problems.
So a better way to write it is to pass inrender
The function in is defined as an instance method, so even if we render many times, the bound function is always the same function.
//Good example
class MouseTracker extends React.Component {
renderCat(mouse) {
return
}
render() {
return (
)
}
}
render props
Advantages and disadvantages of
-
advantage
- Props naming can be modified, and there is no mutual coverage;
- Know the source of props;
- There will be no multi-level nesting of components;
-
shortcoming
-
Cumbersome writing;
-
Cannot be in
return
Accessing data outside the statement; -
It is easy to produce function callback nesting;
The following code:
const MyComponent = () => { return ( {({ x, y }) => ( {({ x: pageX, y: pageY }) => ( {({ api }) => { // yikes }} )} )} ) }
-
Hook
React
The core of is components, so,React
Has been committed to optimizing and improving the way components are declared. From the earliestClass component
, and thenFunction component
, each has its advantages and disadvantages.Class component
It can provide us with a complete life cycle and state, but it is very cumbersome in writing, andFunction component
Although the writing method is very simple and light, its limitation isIt must be a pure function, cannot contain state, and does not support lifecycle, soClass component
Cannot replaceFunction component
。
andReact
The team feelsThe best way to write a component should be a function, not a class, resulting inReact Hooks
。
The design purpose of react hooks is to enhance the function components, and write a fully functional component without using “classes”。
WhyClass component
“Bulky”, borrowedReact
Official examples:
import React, { Component } from "react"
export default class Button extends Component {
constructor() {
super()
this.state = { buttonText: "Click me, please" }
this.handleClick = this.handleClick.bind(this)
}
handleClick() {
this.setState(() => {
return { buttonText: "Thanks, been clicked!" }
})
}
render() {
const { buttonText } = this.state
return {buttonText}
}
}
The above is a simple button component, including the most basic state and click method. After clicking the button, the state changes.
This is a very simple functional component, but it needs a lot of code to implement. becauseFunction component
State is not included, so we cannot use itFunction component
To declare a component with the above functions. But we can useHook
To achieve:
import React, { useState } from "react"
export default function Button() {
const [buttonText, setButtonText] = useState("Click me, please")
function handleClick() {
return setButtonText("Thanks, been clicked!")
}
return {buttonText}
}
Comparatively speaking,Hook
It is lighter and closer toFunction component
At the same time, I kept my state.
The first hook is introduced in the above exampleuseState()
, in addition,React
The official also provideduseEffect()
、useContext()
、useReducer()
Wait for the hook. For details of specific hooks and their usage, seeofficial。
Hook
In addition to the official basic hooks, we can also use these basic hooks to encapsulate and customize hooks, so as to achieve easier code reuse.
Hook advantages and disadvantages
- advantage
- Easier to reuse code;
- Refreshing code style;
- Less code;
- shortcoming
- The state is not synchronized (functions run independently, and each function has an independent scope)
- Need more reasonable use
useEffect
- The granularity is small, and it needs to abstract a lot for complex logic
hook
summary
exceptMixin
In addition to being slightly backward due to its obvious defects, forHigh order components
、render props
、react hook
In general, there is no way to callBest solution
, they are both advantages and disadvantages. Even the hottestreact hook
, although eachhook
It seems to be so brief and refreshing, but in actual business, usually one business function corresponds to multiplehook
, which means that when the business changes, you need to maintain multiplehook
To maintain aclass
In general, the mental burden may increase a lot. Only the way that suits your business isBest solution
。
Reference documents:
- Use of react mixin
- Mixins Considered Harmful
- Higher-Order Components
- Render Props
- React picks up: render props and its usage scenarios
- Hook introduction
Welcome to bump lab blog:aotu.io
Or follow aotulabs official account and push articles from time to time: