Let’s start with the chestnuts

For example, there is a function that has an area in the page, and when the mouse moves over the area, there is a circle that needs to follow the mouse; In the next area, the mouse moves over the area to show the point of the mouse relative to the area. So our previous implementation would have looked like this:

import React, { createRef, PureComponent } from 'react'

// Movable ball
export default class MoveBall extends PureComponent {
    state = {
        x: 0.y: 0
    }
    areaRef = createRef()
    handleMove = e= > {
        const {left, top} = this.areaRef.current.getBoundingClientRect()
        const x = ~~(e.clientX - left)
        const y = ~~(e.clientY - top)
        this.setState({ x, y })
    }
    render() {
        return (
            <div
                ref={this.areaRef}
                className="area"
                onMouseMove={this.handleMove}
            >
                <div className="circle" style={{
                    left: this.state.x - 40.top: this.state.y - 40}} / >
            </div>)}}// Display the mouse position
export default class ShowPoint extends PureComponent {
    state = {
        x: 0.y: 0
    }
    areaRef = createRef()
    handleMove = e= > {
        const {left, top} = this.areaRef.current.getBoundingClientRect()
        const x = ~~(e.clientX - left)
        const y = ~~(e.clientY - top)
        this.setState({ x, y })
    }
    render() {
        return (
            <div
                ref={this.areaRef}
                className="area"
                onMouseMove={this.handleMove}
            >
                <div>
                    mouse left: {this.state.x},
                    mouse top: {this.state.y}
                </div>
            </div>)}}Copy the code

As shown in the code above, some components have exactly the same functionality and processing logic, just different page content. In this case, there are two common solutions:

1. The use of HOC

The functional logic part is extracted into a high-order component, which is roughly implemented as follows:

import React, {createRef, PureComponent} from 'react'
export default function withMove(Comp) {
    return class extends PureComponent {
        state = {
            x: 0.y: 0
        }
        areaRef = createRef()
        handleMove = e= > {
            // The same as the above code...
        }
        render() {
            return (
                <div
                    ref={this.areaRef}
                    className="area"
                    onMouseMove={this.handleMove}
                >
                     <Comp {. this.props} {. this.state} / >
                </div>)}}}// External use
import withMove from './hoc/withMove'
function RenderPoint(props) {
    const {x, y} = props
    return <p>Left: {x}, Top: {y}</p>
}
const ShowPoint = withMove(RenderPoint)
export default ShowPoint
Copy the code

2. Use render props

Just like the use of ctx.Consumer in the React Learning Context (Old and New) article, I can pull out the mouse moving component and convention the passed props. Children or any property as a function. Just call the function and pass the arguments. In this way, the mouse movement can be reused, and the actual rendered content can be returned by the function when the component is used, as shown in the following example:

import React, { createRef, PureComponent } from 'react'
export default class MouseMove extends PureComponent {
    state = {
        x: 0.y: 0
    }
    areaRef = createRef()
    handleMove = e= > {
        // The same as the above code...
    }
    render() {
        return (
            <div
                ref={this.areaRef}
                className="area"
                onMouseMove={this.handleMove}
            >
                {this.props.render(this.state)}
            </div>)}}// For external use:
import React, { memo } from 'react'
import MouseMove from './MouseMove'
const renderPoint = pt= > <p>Left: {pt.x}, Top: {pt.y}</p>

function ShowPoint() {
    return <MouseMove render={renderPoint} />
}
export default memo(ShowPoint)
Copy the code

Pay attention to the point

  • A component requires a property that is a function whose return value is used to render the interface
  • The parameters of the function are passed as data required for rendering the interface
  • Use pure components to avoid passing in a new function each time, resulting in unnecessary rerendering
  • You usually use attributesrender(But the implementation is just calling a function from a property, so the property name is up to you)