国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

React 深入系列6:高階組件

2shou / 492人閱讀

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

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

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

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

2. 應用場景

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

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

import React, { Component } from "react"

class MyComponent extends Component {

  componentWillMount() {
      let data = localStorage.getItem("data");
      this.setState({data});
  }
  
  render() {
    return 
{this.state.data}
} }

代碼很簡單,但當有其他組件也需要從LocalStorage中獲取同樣的數據展示出來時,需要在每個組件都重復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} 把傳遞給當前組件的屬性繼續傳遞給被包裝的組件WrappedComponent
      return 
    }
  }
}

class MyComponent2 extends Component {  
  render() {
    return 
{this.props.data}
} } const MyComponentWithPersistentData = withPersistentData(MyComponent2)

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

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

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

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} 把傳遞給當前組件的屬性繼續傳遞給被包裝的組件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的值的需求了。高階組件中的參數當然也可以是函數,我們將在下一節進一步說明。

3. 進階用法

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

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} 把傳遞給當前組件的屬性繼續傳遞給被包裝的組件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);

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

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

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

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

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

我們可以把它拆分來看:

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

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

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

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

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

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

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

4.與父組件區別

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

5. 注意事項

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

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

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

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

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

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

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

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

我的新書《React進階之路》已上市,請大家多多支持!
鏈接:京東 當當

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/95196.html

相關文章

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

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

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

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

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

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

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

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

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

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

    cncoder 評論0 收藏0

發表評論

0條評論

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