成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

React 深入系列6:高階組件

2shou / 503人閱讀

摘要:在項(xiàng)目中用好高階組件,可以顯著提高代碼質(zhì)量。高階組件的定義類比于高階函數(shù)的定義。高階函數(shù)接收函數(shù)作為參數(shù),并且返回值也是一個函數(shù)。

React 深入系列,深入講解了React中的重點(diǎn)概念、特性和模式等,旨在幫助大家加深對React的理解,以及在項(xiàng)目中更加靈活地使用React。
1. 基本概念

高階組件是React 中一個很重要且比較復(fù)雜的概念,高階組件在很多第三方庫(如Redux)中都被經(jīng)常使用。在項(xiàng)目中用好高階組件,可以顯著提高代碼質(zhì)量。

高階組件的定義類比于高階函數(shù)的定義。高階函數(shù)接收函數(shù)作為參數(shù),并且返回值也是一個函數(shù)。類似的,高階組件接收React組件作為參數(shù),并且返回一個新的React組件。高階組件本質(zhì)上也是一個函數(shù),并不是一個組件,這一點(diǎn)一定不要弄錯。

2. 應(yīng)用場景

為什么React引入高階組件的概念?它到底有何威力?讓我們先通過一個簡單的例子說明一下。

假設(shè)有一個組件MyComponent,需要從LocalStorage中獲取數(shù)據(jù),然后渲染數(shù)據(jù)到界面。我們可以這樣寫組件代碼:

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)有其他組件也需要從LocalStorage中獲取同樣的數(shù)據(jù)展示出來時,需要在每個組件都重復(fù)componentWillMount中的代碼,這顯然是很冗余的。下面讓我們來看看使用高階組件可以怎么改寫這部分代碼。

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)

withPersistentData就是一個高階組件,它返回一個新的組件,在新組件的componentWillMount中統(tǒng)一處理從LocalStorage中獲取數(shù)據(jù)的邏輯,然后將獲取到的數(shù)據(jù)以屬性的方式傳遞給被包裝的組件WrappedComponent,這樣在WrappedComponent中就可以直接使用this.props.data獲取需要展示的數(shù)據(jù)了,如MyComponent2所示。當(dāng)有其他的組件也需要這段邏輯時,繼續(xù)使用withPersistentData這個高階組件包裝這些組件就可以了。

通過這個例子,可以看出高階組件的主要功能是封裝并分離組件的通用邏輯,讓通用邏輯在組件間更好地被復(fù)用。高階組件的這種實(shí)現(xiàn)方式,本質(zhì)上是一個裝飾者設(shè)計(jì)模式。

高階組件的參數(shù)并非只能是一個組件,它還可以接收其他參數(shù)。例如,組件MyComponent3需要從LocalStorage中獲取key等于name的數(shù)據(jù),而不是上面例子中寫死的key等于data的數(shù)據(jù),withPersistentData這個高階組件就不滿足我們的需求了。我們可以讓它接收額外的一個參數(shù),來決定從LocalStorage中獲取哪個數(shù)據(jù):

import React, { Component } from "react"

function withPersistentData(WrappedComponent, key) {
  return class extends Component {
    componentWillMount() {
      let data = localStorage.getItem(key);
        this.setState({data});
    }
    
    render() {
      // 通過{...this.props} 把傳遞給當(dāng)前組件的屬性繼續(xù)傳遞給被包裝的組件WrappedComponent
      return 
    }
  }
}

class MyComponent2 extends Component {  
  render() {
    return 
{this.props.data}
} //省略其他邏輯... } class MyComponent3 extends Component { render() { return
{this.props.data}
} //省略其他邏輯... } const MyComponent2WithPersistentData = withPersistentData(MyComponent2, "data"); const MyComponent3WithPersistentData = withPersistentData(MyComponent3, "name");

新版本的withPersistentData就滿足我們獲取不同key的值的需求了。高階組件中的參數(shù)當(dāng)然也可以是函數(shù),我們將在下一節(jié)進(jìn)一步說明。

3. 進(jìn)階用法

高階組件最常見的函數(shù)簽名形式是這樣的:

HOC([param])([WrappedComponent])

用這種形式改寫withPersistentData,如下:

import React, { Component } from "react"

const withPersistentData = (key) => (WrappedComponent) => {
  return class extends Component {
    componentWillMount() {
      let data = localStorage.getItem(key);
        this.setState({data});
    }
    
    render() {
      // 通過{...this.props} 把傳遞給當(dāng)前組件的屬性繼續(xù)傳遞給被包裝的組件WrappedComponent
      return 
    }
  }
}

class MyComponent2 extends Component {  
  render() {
    return 
{this.props.data}
} //省略其他邏輯... } class MyComponent3 extends Component { render() { return
{this.props.data}
} //省略其他邏輯... } const MyComponent2WithPersistentData = withPersistentData("data")(MyComponent2); const MyComponent3WithPersistentData = withPersistentData("name")(MyComponent3);

實(shí)際上,此時的withPersistentData和我們最初對高階組件的定義已經(jīng)不同。它已經(jīng)變成了一個高階函數(shù),但這個高階函數(shù)的返回值是一個高階組件。HOC([param])([WrappedComponent])這種形式中,HOC([param])才是真正的高階組件,我們可以把它看成高階組件的變種形式。這種形式的高階組件因其特有的便利性——結(jié)構(gòu)清晰(普通參數(shù)和被包裹組件分離)、易于組合,大量出現(xiàn)在第三方庫中。如react-redux中的connect就是一個典型。connect的定義如下:

connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])(WrappedComponent)

這個函數(shù)會將一個React組件連接到Redux 的 store。在連接的過程中,connect通過函數(shù)類型的參數(shù)mapStateToProps,從全局store中取出當(dāng)前組件需要的state,并把state轉(zhuǎn)化成當(dāng)前組件的props;同時通過函數(shù)類型的參數(shù)mapDispatchToProps,把當(dāng)前組件用到的Redux的action creators,以props的方式傳遞給當(dāng)前組件。

例如,我們把組件ComponentA連接到Redux上的寫法類似于:

const ConnectedComponentA = connect(mapStateToProps, mapDispatchToProps)(ComponentA);

我們可以把它拆分來看:

// connect 是一個函數(shù),返回值enhance也是一個函數(shù)
const enhance = connect(mapStateToProps, mapDispatchToProps);
// enhance是一個高階組件
const ConnectedComponentA = enhance(ComponentA);

當(dāng)多個函數(shù)的輸出和它的輸入類型相同時,這些函數(shù)是很容易組合到一起使用的。例如,有f,g,h三個高階組件,都只接受一個組件作為參數(shù),于是我們可以很方便的嵌套使用它們:f( g( h(WrappedComponent) ) )。這里可以有一個例外,即最內(nèi)層的高階組件h可以有多個參數(shù),但其他高階組件必須只能接收一個參數(shù),只有這樣才能保證內(nèi)層的函數(shù)返回值和外層的函數(shù)參數(shù)數(shù)量一致(都只有1個)。

例如我們將connect和另一個打印日志的高階組件withLog聯(lián)合使用:

const ConnectedComponentA = connect(mapStateToProps)(withLog(ComponentA));

這里我們定義一個工具函數(shù):compose(...functions),調(diào)用compose(f, g, h) 等價(jià)于 (...args) => f(g(h(...args)))。用compose函數(shù)我們可以把高階組件嵌套的寫法打平:

const enhance = compose(
  connect(mapStateToProps),
  withLog
);
const ConnectedComponentA = enhance(ComponentA);

像Redux等很多第三方庫都提供了compose的實(shí)現(xiàn),compose結(jié)合高階組件使用,可以顯著提高代碼的可讀性和邏輯的清晰度。

4.與父組件區(qū)別

有些同學(xué)可能會覺得高階組件有些類似父組件的使用。例如,我們完全可以把高階組件中的邏輯放到一個父組件中去執(zhí)行,執(zhí)行完成的結(jié)果再傳遞給子組件。從邏輯的執(zhí)行流程上來看,高階組件確實(shí)和父組件比較相像,但是高階組件強(qiáng)調(diào)的是邏輯的抽象。高階組件是一個函數(shù),函數(shù)關(guān)注的是邏輯;父組件是一個組件,組件主要關(guān)注的是UI/DOM。如果邏輯是與DOM直接相關(guān)的,那么這部分邏輯適合放到父組件中實(shí)現(xiàn);如果邏輯是與DOM不直接相關(guān)的,那么這部分邏輯適合使用高階組件抽象,如數(shù)據(jù)校驗(yàn)、請求發(fā)送等。

5. 注意事項(xiàng)

1)不要在組件的render方法中使用高階組件,盡量也不要在組件的其他生命周期方法中使用高階組件。因?yàn)楦唠A組件每次都會返回一個新的組件,在render中使用會導(dǎo)致每次渲染出來的組件都不相等(===),于是每次render,組件都會卸載(unmount),然后重新掛載(mount),既影響了效率,又丟失了組件及其子組件的狀態(tài)。高階組件最適合使用的地方是在組件定義的外部,這樣就不會受到組件生命周期的影響了。

2)如果需要使用被包裝組件的靜態(tài)方法,那么必須手動拷貝這些靜態(tài)方法。因?yàn)楦唠A組件返回的新組件,是不包含被包裝組件的靜態(tài)方法。hoist-non-react-statics可以幫助我們方便的拷貝組件所有的自定義靜態(tài)方法。有興趣的同學(xué)可以自行了解。

3)Refs不會被傳遞給被包裝組件。盡管在定義高階組件時,我們會把所有的屬性都傳遞給被包裝組件,但是ref并不會傳遞給被包裝組件。如果你在高階組件的返回組件中定義了ref,那么它指向的是這個返回的新組件,而不是內(nèi)部被包裝的組件。如果你希望獲取被包裝組件的引用,你可以把ref的回調(diào)函數(shù)定義成一個普通屬性(給它一個ref以外的名字)。下面的例子就用inputRef這個屬性名代替了常規(guī)的ref命名:

function FocusInput({ inputRef, ...rest }) {
  return ;
}

//enhance 是一個高階組件
const EnhanceInput = enhance(FocusInput);

// 在一個組件的render方法中...
return ( {
    this.input = input
  }
}>)

// 讓FocusInput自動獲取焦點(diǎn)
this.input.focus();
下篇預(yù)告:

React 深入系列7:React 常用模式

我的新書《React進(jìn)階之路》已上市,請大家多多支持!
鏈接:京東 當(dāng)當(dāng)

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/95196.html

相關(guān)文章

  • React 深入系列7:React 常用模式

    摘要:本篇是深入系列的最后一篇,將介紹開發(fā)應(yīng)用時,經(jīng)常用到的模式,這些模式并非都有官方名稱,所以有些模式的命名并不一定準(zhǔn)確,請讀者主要關(guān)注模式的內(nèi)容。 React 深入系列,深入講解了React中的重點(diǎn)概念、特性和模式等,旨在幫助大家加深對React的理解,以及在項(xiàng)目中更加靈活地使用React。 本篇是React深入系列的最后一篇,將介紹開發(fā)React應(yīng)用時,經(jīng)常用到的模式,這些模式并非都有...

    Chao 評論0 收藏0
  • 學(xué)習(xí)es7的Decorator(順帶寫個react高階組件)

    摘要:為了代碼進(jìn)一步解耦,可以考慮使用高階組件這種模式。開源的高階組件使用提供了一系列使用的高階組件,可以增強(qiáng)組件的行為,可以利用此庫學(xué)習(xí)高階組件的寫法。通過使用此庫提供的高階組件,可以方便地讓列表元素可拖動。 1. Decorator基本知識 在很多框架和庫中看到它的身影,尤其是React和Redux,還有mobx中,那什么是裝飾器呢。 修飾器(Decorator)是一個函數(shù),用來修改類的...

    xiyang 評論0 收藏0
  • 深入淺出React高階組件

    摘要:博客地址背景知識在開始講述高階組件前,我們先來回顧高階函數(shù)的定義接收函數(shù)作為輸入,或者輸出另一個函數(shù)的一類函數(shù),被稱作高階函數(shù)。 博客地址:http://www.luckyjing.com/post... 背景知識 在開始講述高階組件前,我們先來回顧高階函數(shù)的定義:接收函數(shù)作為輸入,或者輸出另一個函數(shù)的一類函數(shù),被稱作高階函數(shù)。對于高階組件,它描述的便是接受React組件作為輸入,輸出...

    yuanzhanghu 評論0 收藏0
  • React高階組件

    摘要:結(jié)語高階函數(shù)對于初學(xué)者來說可能不太好理解,但當(dāng)你深入其中,了解其中的原理之后,我們可以使用高階函數(shù)來完成很多的工作。 前段時間在工作中寫Hybrid頁面時遇到了這樣的一個場景,公司需要一系列的活動組件,在每個組件注冊的時候都需要調(diào)用App端提供的一個接口。一開始也考慮了幾種方式,包括mixin、組件繼承以及react高階組件。但經(jīng)過了種種衡量,最后選擇使用了高階組件的做法。 1、Mix...

    ThinkSNS 評論0 收藏0
  • React高階組件

    摘要:高階組件高階函數(shù)接收函數(shù)作為輸入,或者輸出另一個函數(shù)的一類函數(shù)高階組件接收組件作為輸入,輸出一個新的組件的組件。包含了一系列實(shí)用的高階組件庫拖動庫深入理解高階組件其中詳細(xì)介紹了屬性代理和反向繼承的區(qū)別。 React高階組件 高階函數(shù): 接收函數(shù)作為輸入,或者輸出另一個函數(shù)的一類函數(shù); 高階組件: 接收React組件作為輸入,輸出一個新的React組件的組件。 高階組件通過包裹一個新傳入...

    cncoder 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<