React HOC高階組件深入講解
1. 概念
高階組件和高階函數(shù)的類似,使用函數(shù)接收一個(gè)組件,并返回一個(gè)組件。
function withList(WrapComponent) {
return class extends Component {
render() {
return <div><WrapComponent {...this.props}/></div>;
}
}
};
高階組件主要用作于邏輯的封裝、攔截渲染、攔截生命周期:獲取渲染性能,日志打點(diǎn)等,安按照實(shí)現(xiàn)方式可以分為屬性代理和反向繼承兩種。
2. 屬性代理
屬性代理的作用:
- 代理props
- 條件渲染
- 添加狀態(tài)(state)
- 封裝一些通用的邏輯
2.1 代理props
function withList(WrapComponent) {
const data = [{ id: '1', text: '測(cè)試1' }, { id: '2', text: '測(cè)試2' }, { id: '3', text: '測(cè)試3' }, { id: '4', text: '測(cè)試4' }, { id: '5', text: '測(cè)試5' }]
return class extends Component {
render() {
return <div>
{this.props.data.length > 0 ? <WrapComponent {...this.props} data={data} /> : <span>{emptyText}</span>}
</div>;
}
}
};
class List extends Component {
render() {
return (
<ul>
{this.props.data.map(item => {
return <li key={item.id}>{item.text}</li>
})}
</ul>
)
}
};
export default withList(List);2.2 條件渲染
function withList(WrapComponent, emptyText) {
return class extends Component {
render() {
return <div>
{this.props.data.length>0 ? <WrapComponent {...this.props}/> : <span>{emptyText}</span>}
</div>;
}
}
};
class List extends Component {
render() {
return (
<ul>
{this.props.data.map(item => {
return <li key={item.id}>{item.text}</li>
})}
</ul>
)
}
};
export default withList(List,'暫無(wú)數(shù)據(jù)');2.3 添加狀態(tài)
利用這一點(diǎn)可以將非受控組件轉(zhuǎn)為受控組件
import React, { Component } from 'react'
class Input extends Component {
render() {
return (
<input value={this.props.value} />
)
}
};
function withInput(WrapComponent) {
return class extends Component {
state = {
value: this.props.value
}
onChange = (value) => {
this.setState({ value });
}
render() {
return <WrapComponent {...this.props} value={this.state.value} onChange={this.onChange}/>;
}
}
};
export default withInput(Input);3. 反向繼承
- 反向繼承的作用
- 攔截渲染
- 代理props
- 劫持生命周期函數(shù)
- 操作state
- 修改react樹(shù)
3.1 攔截渲染
function withList(WrapComponent) {
return class extends WrapComponent {
render() {
return <div>
<span>通過(guò)反向繼承攔截渲染</span>
{super.render()}
</div>;
}
}
};
3.2 劫持生命周期
function withList(WrapComponent) {
return class extends WrapComponent {
componentDidMount(){
if(super.componentDidMount){
super.componentDidMount.apply(this);
};
console.log('攔截生命周期');
}
render() {
return <div>
<span>通過(guò)反向繼承攔截渲染</span>
{super.render()}
</div>;
}
}
};
3.3 操作state
import React, { Component } from 'react';
function withList(WrapComponent) {
return class extends WrapComponent {
constructor(props) {
super(props);
this.state.data = []; //將列表數(shù)據(jù)置空
}
render() {
return <div>{super.render()}</div>
}
}
};
class List extends Component {
state = {
data: [{ id: '1', text: '測(cè)試1' }, { id: '2', text: '測(cè)試2' }, { id: '3', text: '測(cè)試3' }, { id: '4', text: '測(cè)試4' }, { id: '5', text: '測(cè)試5' }],
}
render() {
return (
<ul>
{this.state.data.map(item => {
return <li key={item.id}>{item.text}</li>
})}
</ul>
)
}
};
export default withList(List);
3.4 修改react樹(shù)
import React, { Component } from 'react';
function withList(WrapComponent) {
return class extends WrapComponent {
render() {
const tree = super.render();
let newProps = { ...tree.props };
if (tree.type === 'ul') {
newProps.value = 'value';
}
return React.cloneElement(tree, newProps, newProps.children);
}
}
};
class List extends Component {
render() {
return (
<ul>
{this.props.data.map(item => {
return <li key={item.id}>{item.text}</li>
})}
</ul>
)
}
};
export default withList(List);3.5 記錄渲染性能
function withTime(WrapComponent) {
return class extends WrapComponent {
constructor(props) {
super(props);
this.start = 0;
this.end = 0
}
componentWillMount() {
if (super.componentWillMount) {
super.componentWillMount.call(this);
};
this.start = Date.now();
}
componentDidMount() {
if (super.componentDidMount) {
super.componentDidMount.call(this);
};
this.end = Date.now();
console.log(`渲染的時(shí)間為:${(this.end - this.start) / 1000}秒`)
}
render() {
return super.render();
}
}
};4. 使用裝飾器
4.1 安裝和配置
首先執(zhí)行npm run eject暴露出webpack配置,然后安裝裝飾器插件
yarn add @babel/plugin-proposal-decoreators;
最后在package.json中的babel配置中添加一下配置然后重新項(xiàng)目
"babel": {
"presets": [
"react-app"
],
"plugins":[
[
"@babel/plugin-proposal-decorators",
{"legacy":true}
]
]
}
配置完之后如果有報(bào)紅需要配置一下:
文件-> 首選項(xiàng) -> 搜索 ExperimentalDecorators 勾選上之后紅線就消失了
4.2 使用
@withList
class List extends Component {
render() {
return (
<ul>
{this.props.data.map(item => {
return <li key={item.id}>{item.text}</li>
})}
</ul>
)
}
};
5.總結(jié)
- 高階組件的作用有代復(fù)用、代理屬性、攔截渲染、劫持生命周期
- 反向繼承能直接操作和攔截組件的state和生命周期,功能比屬性代理更加強(qiáng)大
到此這篇關(guān)于React HOC高階組件深入講解的文章就介紹到這了,更多相關(guān)React HOC 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解react-navigation6.x路由庫(kù)的基本使用
最近兩個(gè)項(xiàng)目都用到了React Navigation,所以就研究一下如何使用,本文主要介紹了react-navigation6.x路由庫(kù)的基本使用,感興趣的可以了解一下2021-11-11
ReactNative頁(yè)面跳轉(zhuǎn)Navigator實(shí)現(xiàn)的示例代碼
本篇文章主要介紹了ReactNative頁(yè)面跳轉(zhuǎn)Navigator實(shí)現(xiàn)的示例代碼,具有一定的參考價(jià)值,有興趣的可以了解一下2017-08-08
React Native中WebView與html雙向通信遇到的坑
這篇文章主要介紹了React Native中WebView與html雙向通信的一些問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2023-01-01
react render的原理及觸發(fā)時(shí)機(jī)說(shuō)明
這篇文章主要介紹了react render的原理及觸發(fā)時(shí)機(jī)說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02
React+Antd+Redux實(shí)現(xiàn)待辦事件的方法
這篇文章主要介紹了React+Antd+Redux實(shí)現(xiàn)待辦事件的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03
React?Native項(xiàng)目設(shè)置路徑別名示例
這篇文章主要為大家介紹了React?Native項(xiàng)目設(shè)置路徑別名實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05

