Higher Order Components

使用 HOC 进行代码复用

假设存在下面两个组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import React from "react"

class ButtonCounter extends React.Component {
constructor(props) {
super(props)

this.state = {
count: 0,
}
}

increase = () => {
let { step } = this.props

this.setState((pre) => {
return {
count: pre.count + step,
}
})
}

render() {
let { count } = this.state

return <button onClick={this.increase}>click {count} times</button>
}
}

export default ButtonCounter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import React from "react"

class ButtonCounter extends React.Component {
constructor(props) {
super(props)

this.state = {
count: 0,
}
}

increase = () => {
let { step } = this.props

this.setState((pre) => {
return {
count: pre.count + step,
}
})
}

render() {
let { count } = this.state

return <div onMouseLeave={this.increase}>click {count} times</div>
}
}

export default ButtonCounter

使用 HOC 进行改造

HOC 通过传入的组件,返回一个新的组件。

1
2
3
4
5
6
7
8
9
10
11
12
13
import React from "react"

const withCounter = (OriginalComponent) => {
class newComponent extends React.Component {
render() {
return <OriginalComponent />
}
}

return newComponent
}

export default withCounter

将 counter 中的方法放到 HOC 中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import React from "react"

const withCounter = (OriginalComponent, step) => {
// 将step从props中抽离出来
class newComponent extends React.Component {
constructor(props) {
super(props)

this.state = {
count: 0,
}
}

increase = () => {
this.setState((pre) => {
return {
count: pre.count + step,
}
})
}

render() {
let { count } = this.state

return (
<OriginalComponent
increase={this.increase}
count={count}
{...this.props}
/>
)
}
}

return newComponent
}

export default withCounter
1
2
3
4
5
6
7
8
9
10
11
12
13
import React from "react"

import withCounter from "../util/withCounter"

class ButtonCounter extends React.Component {
render() {
let { increase, count } = this.props

return <button onClick={increase}>click {count} times</button>
}
}

export default withCounter(ButtonCounter, 2)