官方定義
高階組件(HOC)是 React 中用于<span style="color:red">復(fù)用組件邏輯</span>的一種高級(jí)技巧。HOC 自身不是 React API 的一部分,它是一種基于 React 的組合特性而形成的設(shè)計(jì)模式。
HOC 是單詞 Heigher Order Component 縮寫
具體而言,<span style="color:red">高階組件是參數(shù)為組件,返回值為新組件的函數(shù)。
const EnhancedComponent = higherOrderComponent(WrappedComponent);
從官方定義中,我們可以抽取以下重點(diǎn):
- 高階組件就是一個(gè)函數(shù).
- 此函數(shù)接受一個(gè)組件作為參數(shù).
- 此函數(shù)返回一個(gè)組件.
- <span style="color:red"> 邏輯復(fù)用.或者說(shuō)組件的功能擴(kuò)展.
高階組價(jià),接受一個(gè)構(gòu)造函數(shù),返回一個(gè)構(gòu)造函數(shù). 所以,高階組件就是一個(gè)概念. 它本質(zhì)上也是高階函數(shù).
react-redux 里面的 connect 函數(shù),就是一個(gè)高階組件.

理解高階組件.
既然高階組件,本質(zhì)上是一個(gè)函數(shù).那么我就給它一個(gè)組件作為入?yún)?在返回一個(gè)組件即可.
import React, { useState } from 'react'
import './App.css';
/**
*
* 官方定義高階組件(HOC)是 React 中用于**復(fù)用組件邏輯**的一種高級(jí)技巧。HOC 自身不是 React API 的一部分,它是一種基于 React 的組合特性而形成的設(shè)計(jì)模式。
HOC 是單詞 Heigher Order Component 縮寫
具體而言,高階組件是參數(shù)為組件,返回值為新組件的函數(shù)。
*
*
*/
function HelloComponent(props) {
return (
<div>
<h2>我是一個(gè)定義的函數(shù)式組件 <span style={{ fontSize: '20px', color: '#f40' }}>{props.title}</span> </h2>
</div>
)
}
// 高階組件就是一個(gè)函數(shù),接收一個(gè)組件,返回一個(gè)[新]的組件.
const withComponent = (Component) => {
return function WrapperComponent() {
const [title, setTitle] = useState('這是由內(nèi)部組件 WrapperComponent 傳遞過來(lái)的 title')
const changeTitle = () => {
setTitle("這是新的 title")
}
return (
<React.Fragment>
<Component title={title} />
<button onClick={changeTitle}>修改 title</button>
</React.Fragment>
)
}
}
// 傳入一個(gè)HelloComponent,作為入?yún)?// 返回一個(gè)HocComponent作為新的組件
const HocComponent = withComponent(HelloComponent)
function App() {
return (
<div className="App">
<h2>Hello HOC - Highter Order Component</h2>
<HocComponent />
</div>
);
}
export default App;
可以正常工作.
![高階組件簡(jiǎn)單使用images.jianshu.io/upload_images/2701794-d79d78664a4895aa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
將邏輯復(fù)用(功能擴(kuò)展)邏輯設(shè)定在高階組件中.
上述例子,僅演示了高階組件的用法和原理.
這次,我們把邏輯復(fù)用和功能擴(kuò)展加上去.
這么一個(gè)例子
- 有兩組件.
Foo和Bar. -
Foo和Bar組件的功能就是在屏幕視口寬度發(fā)生改變是,動(dòng)態(tài)的把寬度數(shù)值顯示出來(lái).
import React from 'react'
import './App.css';
/**
*
* 官方定義高階組件(HOC)是 React 中用于**復(fù)用組件邏輯**的一種高級(jí)技巧。HOC 自身不是 React API 的一部分,它是一種基于 React 的組合特性而形成的設(shè)計(jì)模式。
HOC 是單詞 Heigher Order Component 縮寫
具體而言,高階組件是參數(shù)為組件,返回值為新組件的函數(shù)。
*
*
*/
class Foo extends React.PureComponent {
state = {
sw: document.documentElement.clientWidth
}
componentDidMount () {
window.addEventListener('resize', () => {
this.setState(() => ({ sw: document.documentElement.clientWidth }))
}, false)
}
componentWillUnmount () {
window.removeEventListener('resize')
}
render () {
return (
<p className='FooContent'>當(dāng)前的屏幕寬度為:{this.state.sw}</p>
)
}
}
class Bar extends React.PureComponent {
state = {
sw: document.documentElement.clientWidth
}
componentDidMount () {
window.addEventListener('resize', () => {
this.setState(() => ({ sw: document.documentElement.clientWidth }))
}, false)
}
componentWillUnmount () {
window.removeEventListener('resize')
}
render () {
return (
<button className='btn-content'>當(dāng)前屏幕寬度為:{this.state.sw}</button>
)
}
}
function App () {
return (
<div className="App">
<h2>Hello HOC - Highter Order Component</h2>
<Foo />
<Bar />
</div>
);
}
export default App;
效果如圖:
[圖片上傳失敗...(image-c468a2-1642682879317)]
功能確實(shí)實(shí)現(xiàn)了.但是兩組件除了渲染的位置,其他地方都是一致的.
在Vue中,我們可以使用 mixins 來(lái)解決組件間邏輯重復(fù)定義的問題.
state , componentDidMount, componentWillUnmount邏輯重復(fù).
在 React 中,我們就可以使用 Highter Order Component 高階組件的方式,來(lái)抽取組件重復(fù)定義的邏輯部分.
// 定義一個(gè)高階組件函數(shù),來(lái)抽取邏輯重復(fù)的位置,提高邏輯復(fù)用.
const withResize = (Component) => {
//xxxxx
}
具體代碼如下:
import React from 'react'
import './App.css';
/**
*
* 官方定義高階組件(HOC)是 React 中用于**復(fù)用組件邏輯**的一種高級(jí)技巧。HOC 自身不是 React API 的一部分,它是一種基于 React 的組合特性而形成的設(shè)計(jì)模式。
HOC 是單詞 Heigher Order Component 縮寫
具體而言,高階組件是參數(shù)為組件,返回值為新組件的函數(shù)。
*
*
*/
class Foo extends React.PureComponent {
// state = {
// sw: document.documentElement.clientWidth
// }
// componentDidMount () {
// window.addEventListener('resize', () => {
// this.setState(() => ({ sw: document.documentElement.clientWidth }))
// }, false)
// }
// componentWillUnmount () {
// window.removeEventListener('resize')
// }
render () {
return (
<p className='FooContent'>當(dāng)前的屏幕寬度為:{this.props.sw}</p>
)
}
}
class Bar extends React.PureComponent {
// state = {
// sw: document.documentElement.clientWidth
// }
// componentDidMount () {
// window.addEventListener('resize', () => {
// this.setState(() => ({ sw: document.documentElement.clientWidth }))
// }, false)
// }
// componentWillUnmount () {
// window.removeEventListener('resize')
// }
render () {
return (
<button className='btn-content'>當(dāng)前屏幕寬度為:{this.props.sw}</button>
)
}
}
// 定義一個(gè)高階組件函數(shù),來(lái)抽取邏輯重復(fù)的位置,提高邏輯復(fù)用.
const withResize = (Component) => {
return class WrappedComponent extends React.PureComponent {
//#region 抽離組件通用的邏輯部分
state = {
sw: document.documentElement.clientWidth
}
componentDidMount () {
window.addEventListener('resize', () => {
this.setState(() => ({ sw: document.documentElement.clientWidth }))
}, false)
}
componentWillUnmount () {
window.removeEventListener('resize')
}
//#endregion
render () {
// 將需要的數(shù)據(jù)以 props 的方式傳遞給被包裝的組件
return <Component {...this.state} />
}
}
}
const FooWithResize = withResize(Foo)
const BarWithResize = withResize(Bar)
function App () {
return (
<div className="App">
<h2>Hello HOC - Highter Order Component</h2>
<h3>將通用邏輯抽離,以便復(fù)用!</h3>
{/* <Foo />
<Bar /> */}
<FooWithResize />
<BarWithResize />
</div>
);
}
export default App;
- 將通用邏輯從
Foo和Bar組件中抽離.起到邏輯復(fù)用的作用. - 將
Foo和Bar需要的數(shù)據(jù)以props的形式傳入即可.

效果和上述是一致的.
總結(jié)
- 高階組件就是一個(gè)函數(shù)僅此而已(
javascript中不就是函數(shù)和對(duì)象嗎?) - 高階組件接受一個(gè)組件(可以是函數(shù)組件,也可以是class 組件)作為參數(shù)(普通函數(shù),構(gòu)造函數(shù)).
- 返回一個(gè)新組件(可以是函數(shù)組件,也可是 class 組件),返回一個(gè)普通函數(shù)或者是構(gòu)造函數(shù).
- 所以高階組件也是一個(gè)高階函數(shù).
- 將通用的邏輯抽離在高階組件中,已達(dá)到復(fù)用的目的.