新聞中心
本文轉(zhuǎn)載自微信公眾號(hào)「JS每日一題」,作者灰灰。轉(zhuǎn)載本文請(qǐng)聯(lián)系JS每日一題公眾號(hào)。

創(chuàng)新互聯(lián)服務(wù)項(xiàng)目包括棗強(qiáng)網(wǎng)站建設(shè)、棗強(qiáng)網(wǎng)站制作、棗強(qiáng)網(wǎng)頁制作以及棗強(qiáng)網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,棗強(qiáng)網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到棗強(qiáng)省份的部分城市,未來相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!
一、是什么
高階函數(shù)(Higher-order function),至少滿足下列一個(gè)條件的函數(shù)
- 接受一個(gè)或多個(gè)函數(shù)作為輸入
- 輸出一個(gè)函數(shù)
在React中,高階組件即接受一個(gè)或多個(gè)組件作為參數(shù)并且返回一個(gè)組件,本質(zhì)也就是一個(gè)函數(shù),并不是一個(gè)組件
- const EnhancedComponent = highOrderComponent(WrappedComponent);
上述代碼中,該函數(shù)接受一個(gè)組件WrappedComponent作為參數(shù),返回加工過的新組件EnhancedComponent
高階組件的這種實(shí)現(xiàn)方式,本質(zhì)上是一個(gè)裝飾者設(shè)計(jì)模式
二、如何編寫
最基本的高階組件的編寫模板如下:
- import React, { Component } from 'react';
- export default (WrappedComponent) => {
- return class EnhancedComponent extends Component {
- // do something
- render() {
- return
; - }
- }
- }
通過對(duì)傳入的原始組件 WrappedComponent 做一些你想要的操作(比如操作 props,提取 state,給原始組件包裹其他元素等),從而加工出想要的組件 EnhancedComponent
把通用的邏輯放在高階組件中,對(duì)組件實(shí)現(xiàn)一致的處理,從而實(shí)現(xiàn)代碼的復(fù)用
所以,高階組件的主要功能是封裝并分離組件的通用邏輯,讓通用邏輯在組件間更好地被復(fù)用
但在使用高階組件的同時(shí),一般遵循一些約定,如下:
- props 保持一致
- 你不能在函數(shù)式(無狀態(tài))組件上使用 ref 屬性,因?yàn)樗鼪]有實(shí)例
- 不要以任何方式改變?cè)冀M件 WrappedComponent
- 透傳不相關(guān) props 屬性給被包裹的組件 WrappedComponent
- 不要再 render() 方法中使用高階組件
- 使用 compose 組合高階組件
- 包裝顯示名字以便于調(diào)試
這里需要注意的是,高階組件可以傳遞所有的props,但是不能傳遞ref
如果向一個(gè)高階組件添加refe引用,那么ref 指向的是最外層容器組件實(shí)例的,而不是被包裹的組件,如果需要傳遞refs的話,則使用React.forwardRef,如下:
- function withLogging(WrappedComponent) {
- class Enhance extends WrappedComponent {
- componentWillReceiveProps() {
- console.log('Current props', this.props);
- console.log('Next props', nextProps);
- }
- render() {
- const {forwardedRef, ...rest} = this.props;
- // 把 forwardedRef 賦值給 ref
- return
; - }
- };
- // React.forwardRef 方法會(huì)傳入 props 和 ref 兩個(gè)參數(shù)給其回調(diào)函數(shù)
- // 所以這邊的 ref 是由 React.forwardRef 提供的
- function forwardRef(props, ref) {
- return
- }
- return React.forwardRef(forwardRef);
- }
- const EnhancedComponent = withLogging(SomeComponent);
三、應(yīng)用場景
通過上面的了解,高階組件能夠提高代碼的復(fù)用性和靈活性,在實(shí)際應(yīng)用中,常常用于與核心業(yè)務(wù)無關(guān)但又在多個(gè)模塊使用的功能,如權(quán)限控制、日志記錄、數(shù)據(jù)校驗(yàn)、異常處理、統(tǒng)計(jì)上報(bào)等
舉個(gè)例子,存在一個(gè)組件,需要從緩存中獲取數(shù)據(jù),然后渲染。一般情況,我們會(huì)如下編寫:
- import React, { Component } from 'react'
- class MyComponent extends Component {
- componentWillMount() {
- let data = localStorage.getItem('data');
- this.setState({data});
- }
- render() {
- return
{this.state.data}- }
- }
上述代碼當(dāng)然可以實(shí)現(xiàn)該功能,但是如果還有其他組件也有類似功能的時(shí)候,每個(gè)組件都需要重復(fù)寫componentWillMount中的代碼,這明顯是冗雜的
下面就可以通過高價(jià)組件來進(jìn)行改寫,如下:
- import React, { Component } from 'react'
- function withPersistentData(WrappedComponent) {
- return class extends Component {
- componentWillMount() {
- let data = localStorage.getItem('data');
- this.setState({data});
- }
- render() {
- // 通過{...this.props} 把傳遞給當(dāng)前組件的屬性繼續(xù)傳遞給被包裝的組件WrappedComponent
- return
- }
- }
- }
- class MyComponent2 extends Component {
- render() {
- return
{this.props.data}- }
- }
- const MyComponentWithPersistentData = withPersistentData(MyComponent2)
再比如組件渲染性能監(jiān)控,如下:
- class Home extends React.Component {
- render() {
- return (
Hello World.
);- }
- }
- function withTiming(WrappedComponent) {
- return class extends WrappedComponent {
- constructor(props) {
- super(props);
- this.start = 0;
- this.end = 0;
- }
- componentWillMount() {
- super.componentWillMount && super.componentWillMount();
- this.start = Date.now();
- }
- componentDidMount() {
- super.componentDidMount && super.componentDidMount();
- this.end = Date.now();
- console.log(`${WrappedComponent.name} 組件渲染時(shí)間為 ${this.end - this.start} ms`);
- }
- render() {
- return super.render();
- }
- };
- }
- export default withTiming(Home);
參考文獻(xiàn)
https://zh-hans.reactjs.org/docs/higher-order-components.html#gatsby-focus-wrapper
https://zh.wikipedia.org/wiki/%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0
https://segmentfault.com/a/1190000010307650
https://zhuanlan.zhihu.com/p/61711492
當(dāng)前題目:面試官:說說對(duì)高階組件的理解?應(yīng)用場景?
網(wǎng)站路徑:http://fisionsoft.com.cn/article/djihpsi.html


咨詢
建站咨詢
