理解React-組件生命週期

做者-Bartosz Szczeciński原文react

React提供給開發者不少方法或‘鉤子’,調用於一個組件的生命週期,使咱們更新UI和app state。瞭解什麼時候使用哪些對正確理解如何使用React相當重要。git

constructor

constuctors是OOP的基礎——一個不管什麼時候一個新object被建立時被調用的特殊函數。調用一個特殊函數super很是重要,在咱們的class extent任何其它class(也有定義了constructor)時。調用此特殊函數將call 咱們parent class的constructor且容許初始化其自己。此即爲什麼咱們只有在初始化地call了super時纔有權限訪問this.props的緣由。github

如上所述,constructor對於構建咱們組件——建立任何領域(以this.開始的變量)或者初始化以接收到的props爲基礎的state——很是完美。redux

這也是你經過在直接覆蓋this.state之處期待change/set state僅有的字段。在別的其它實例上記得用this.setState.bash

DO服務器

  • set initial state
  • 若未用class屬性語法-準備全部class 字段和bind 將做爲callback傳遞的函數。

DON'Tapp

  • cause any side effects (AJAX calls etc.)

componentWillMount

這是一個特殊狀況 - componentWillMount與構造函數沒有多大區別 - 它只在初始安裝生命週期中被調用一次。 從歷史上看,使用componentWillMountover構造函數有一些緣由,請參閱此react-redux問題,但請記住,此處描述的練習已被棄用。ide

不少人會試圖使用這個函數來發送請求來獲取數據,並但願在初始渲染準備好以前數據可用。 狀況並不是如此 - 當請求在渲染以前被初始化時,在渲染被調用以前它將不能完成。函數

此外,隨着對React Fiber的更改(post React 16 beta版本),此函數最終可能會在初始渲染被調用以前調用屢次,所以可能會致使觸發多重反作用。 因爲這個事實,不推薦使用這個函數來產生任何反作用。post

值得注意的是,在使用服務器端渲染時調用此函數,而在這種狀況下,它不會在服務器上調用對應的componentDidMount,而是在客戶端上調用。 因此若是在服務器部分須要一些反作用,這個函數應該被用做例外。

此函數中使用的setState是「空閒」的,不會觸發從新渲染。

DO

  • update state 經過 this.setState
  • perform last minute optimization(執行最後一分鐘優化)
  • 僅在SSR形成side-effects (AJAX calls etc.)

DON'T

  • 不在CS形成side-effects (AJAX calls etc.)

componentWillReceiveProps(nextProps)

這個函數將在每一個更新生命週期中由props變化(父元素從新渲染)調用,而且將傳遞全部props傳遞的對象圖,不管自上次從新渲染後props值是否已經改變亦或自前個渲染階段。

這個函數是理想的,若是你有一個組件的狀態部分取決於從父組件傳遞的props做爲調用this.setState在這裏不會致使額外的渲染調用。

請記住,因爲全部props都調用了該函數,因此即便對那些沒有改變的props,開發人員也會執行檢查以肯定實際值是否發生了變化,例如:

componentWillReceiveProps(nextProps) {
  if(nextProps.myProp !== this.props.myProps) {
    // nextProps.myProp has a different value than our current prop
    // so we can perform some calculations based on the new value
  }
}
複製代碼

因爲使用React Fiber(16階測試版)這個功能可能會在實際調用renderfunction以前屢次調用,所以不建議在此使用任何反作用致使的操做。

DO

  • sync state to props(同步化state到props)

DON'T

  • 形成side-effects (AJAX calls etc.)

shouldComponentUpdate(nextProps, nextState, nextContext)

默認狀況下,全部基於類的組件都會在它們接收到的props,其狀態或環境發生變化時從新render本身。 若是從新渲染組件是計算重啓(例如生成圖表)或者出於某些性能緣由不推薦使用,則開發人員能夠訪問將在update cycle中調用的特殊函數。

這個函數將在內部調用props,state和object的下一個值。 開發人員可使用它們來驗證更改是否須要從新渲染,並返回false以防止從新渲染髮生。 在其餘狀況下,您預計會返回true。

DO

  • 用於提升perfomance

DON'T

  • 形成side-effects (AJAX calls etc.)
  • call this.setState

componentWillUpdate(nextProps, nextState)

若是shouldComponentUpdate函數未被使用,或者它決定組件在此渲染週期中應更新,則將調用另外一個生命週期函數。 此函數一般用於在state的某些部分基於props時,執行狀態和props同步。

在實現shouldComponentUpdate的狀況下,可使用此函數而不是componentWillReceiveProps,由於只有在實際從新渲染組件時纔會調用此函數。

與全部其餘componentWill *函數相似,此函數可能在渲染前最終調用屢次,所以不建議在此執行致使操做的反作用。 DO

  • synchronize state to props

DON'T

  • 形成side-effects (AJAX calls etc.)

componentDidUpdate(prevProps, prevState, prevContext)

這個函數將在渲染完成後在每一個從新渲染週期中被調用。 這意味着您能夠肯定組件及其全部子組件已正確render其自身。

因爲這是惟一保證在每一個從新render週期中僅被調用一次的函數,所以建議將此函數用於任何致使操做的反作用。 與componentWillUpdate和componentWillReceiveProps相似,即便這些值沒有發生實際更改,也會使用之前的props,state和context的object映射來調用此函數。 由於開發人員須要手動檢查給定的值是否發生了變化,而後才能執行各類更新操做:

componentDidUpdate(prevProps) {
  if(prevProps.myProps !== this.props.myProp) {
    // this.props.myProp has a different value
    // we can perform any operations that would 
    // need the new value and/or cause side-effects 
    // like AJAX calls with the new value - this.props.myProp
  }
}
複製代碼

DO

  • 形成side-effects (AJAX calls etc.)

DON'T

  • call this.setState 因其可致re-render

上述規則的一個例外是基於某些DOM屬性更新狀態,只有在組件從新呈現後才能計算該屬性(例如,某些DOM節點的位置/維度)。 請注意防止更新,若是值實際上沒有更改,可能會致使渲染循環。

componentDidCatch(errorString, errorInfo)

React 16中的新增功能 - 今生命週期方法的特殊之處在於它能夠對發生在子組件中的事件做出反應,特別是對任何子組件中發生的任何未捕獲錯誤。

經過這個添加,你可讓你的父母元素處理錯誤 - 例如 - 設置錯誤信息狀態並在其渲染中返回適當的消息,或者登陸到報告系統,例如:

componentDidCatch(errorString, errorInfo) {
  this.setState({
    error: errorString
  });
  ErrorLoggingTool.log(errorInfo);
}
render() {
  if(this.state.error) return <ShowErrorMessage error={this.state.error} />
  return (
    // render normal component output
  );
}
複製代碼

發生錯誤時,該函數將被調用:

  • errorString - 錯誤的.toString()消息
  • errorInfo - 具備單個字段componentStack的對象,它表示堆棧跟蹤返回錯誤發生的位置,例如:
in Thrower
    in div (created by App)
    in App

複製代碼

componentDidMount

這個函數在給定組件的整個生命週期中只會被調用一次,而且它被調用表示組件及其全部子組件被正確渲染。

因爲這個函數被保證只被調用一次,所以它是完成AJAX請求等引發反作用的操做的理想選擇。

DO

  • 形成side-effects (AJAX calls etc.)

DON'T

  • call this.setState 因其可致re-render

上述規則的一個例外是基於某些DOM屬性更新狀態,只有在組件從新呈現後才能計算該屬性(例如,某些DOM節點的位置/維度)。 請注意防止更新,若是值實際上沒有更改,可能會致使渲染循環。

componentWillUnmount

若是它使用定時器(setTimeout,setInterval),打開套接字或執行咱們須要在再也不須要時關閉/移除的任何操做,則使用此函數在組件後面「清除」。

DO

  • remove any timers or listeners created in lifespan of the component

DON'T

  • call this.setState, start new listeners or timers

Component cycles

組件可能re-render有多種緣由,而且每一個組件中都會調用不一樣的函數,以便開發人員更新組件的某些部分。

  • Component creation(組件建立)

第一個循環是組件的建立,這一般是在解析的JSX🌲中第一次遇到組件時發生的:

  • Component re-rendering due to re-rendering of the parent component(因爲父組件更新而組件更新)

  • Component re-rendering due to internal change (e.g. a call to this.setState())( 因爲內部改變的組件更新)

  • Component re-rendering due to call to this.forceUpdate(因爲call this.forceUpdate而re-render的組件)

  • Component re-rendering due to catching an error(因爲捕獲錯誤而更新組件)

在React 16中引入了「ErrorBoundaries」。 一個組件能夠定義一個特殊的層,它能夠捕獲錯誤並提供一個新的生命週期方法 - componentDidCatch - 它容許開發人員提供自我修復操做以恢復或優雅地處理錯誤。

Shoutout to@James_k_nelson,他剛剛發佈了一個componentWillReceiveProps模擬器,你能夠在reactarmory.com/guides/life…找到並使用它。

相關文章
相關標籤/搜索