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: '測試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)
利用這一點(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樹
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(`渲染的時(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)文章
ReactNative頁面跳轉(zhuǎn)Navigator實(shí)現(xiàn)的示例代碼
本篇文章主要介紹了ReactNative頁面跳轉(zhuǎn)Navigator實(shí)現(xiàn)的示例代碼,具有一定的參考價(jià)值,有興趣的可以了解一下2017-08-08React Native中WebView與html雙向通信遇到的坑
這篇文章主要介紹了React Native中WebView與html雙向通信的一些問題,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2023-01-01react render的原理及觸發(fā)時(shí)機(jī)說明
這篇文章主要介紹了react render的原理及觸發(fā)時(shí)機(jī)說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02React+Antd+Redux實(shí)現(xiàn)待辦事件的方法
這篇文章主要介紹了React+Antd+Redux實(shí)現(xiàn)待辦事件的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03React?Native項(xiàng)目設(shè)置路徑別名示例
這篇文章主要為大家介紹了React?Native項(xiàng)目設(shè)置路徑別名實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05