React HOC高階組件深入講解
1. 概念
高階組件和高階函數(shù)的類似,使用函數(shù)接收一個組件,并返回一個組件。
function withList(WrapComponent) {
return class extends Component {
render() {
return <div><WrapComponent {...this.props}/></div>;
}
}
};
高階組件主要用作于邏輯的封裝、攔截渲染、攔截生命周期:獲取渲染性能,日志打點等,安按照實現(xiàn)方式可以分為屬性代理和反向繼承兩種。
2. 屬性代理
屬性代理的作用:
- 代理props
- 條件渲染
- 添加狀態(tài)(state)
- 封裝一些通用的邏輯
2.1 代理props
function withList(WrapComponent) {
const data = [{ id: '1', text: '測試1' }, { id: '2', text: '測試2' }, { id: '3', text: '測試3' }, { id: '4', text: '測試4' }, { id: '5', text: '測試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,'暫無數(shù)據(jù)');2.3 添加狀態(tài)
利用這一點可以將非受控組件轉(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樹
3.1 攔截渲染
function withList(WrapComponent) {
return class extends WrapComponent {
render() {
return <div>
<span>通過反向繼承攔截渲染</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>通過反向繼承攔截渲染</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: '測試1' }, { id: '2', text: '測試2' }, { id: '3', text: '測試3' }, { id: '4', text: '測試4' }, { id: '5', text: '測試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樹
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(`渲染的時間為:${(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配置中添加一下配置然后重新項目
"babel": {
"presets": [
"react-app"
],
"plugins":[
[
"@babel/plugin-proposal-decorators",
{"legacy":true}
]
]
}
配置完之后如果有報紅需要配置一下:
文件-> 首選項 -> 搜索 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和生命周期,功能比屬性代理更加強大
到此這篇關(guān)于React HOC高階組件深入講解的文章就介紹到這了,更多相關(guān)React HOC 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
ReactNative頁面跳轉(zhuǎn)Navigator實現(xiàn)的示例代碼
本篇文章主要介紹了ReactNative頁面跳轉(zhuǎn)Navigator實現(xiàn)的示例代碼,具有一定的參考價值,有興趣的可以了解一下2017-08-08
React Native中WebView與html雙向通信遇到的坑
這篇文章主要介紹了React Native中WebView與html雙向通信的一些問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2023-01-01
React+Antd+Redux實現(xiàn)待辦事件的方法
這篇文章主要介紹了React+Antd+Redux實現(xiàn)待辦事件的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03

