【全棧React】第7天: 生命週期鉤子函數

本文轉載自:衆成翻譯
譯者:iOSDevLog
連接:http://www.zcfy.cc/article/3827
原文:https://www.fullstackreact.com/30-days-of-react/day-7/react

今天,咱們將看看咱們能夠用於React組件的一些最多見的生命週期鉤子函數,咱們將討論爲何它們是有用的,什麼時間應該用什麼。git

恭喜!咱們已經在React的第一週結束了,咱們已經覆蓋了這麼多的基礎知識。咱們剛剛完成了處理有狀態的組件來跟蹤組件的內部狀態。今天,咱們將暫停實施,並談一下應用中的組件_lives_。也就是說,咱們將討論組件的生命週期。github

因爲React裝載了咱們的應用,它爲咱們提供了一些鉤子,咱們能夠在組件生命週期的不一樣時間插入本身的功能。爲了_hook into_到生命週期,咱們須要在咱們的組件上定義函數,每一個鉤子在適當的時候對其進行調用。讓咱們來看看第一個生命週期鉤子:api

componentWillMount() / componentDidMount()

當咱們的應用中的一個頁面上定義了一個組件時,在定義虛擬節點時,咱們不能當即依賴它在DOM中可用。相反,咱們必須等到組件自己在瀏覽器中其實是_mounted_。對於咱們須要運行的功能,咱們能夠定義兩個不一樣的_hooks_(或函數)。在組件被裝載在頁面以前被調用的一個,在組件被裝載以後被調用的一個。promise

什麼是 mounting?

因爲咱們使用React定義了咱們的DOM樹中的節點的virtual representation,咱們實際上並無定義DOM節點。相反,咱們正在創建一個內存視圖,React爲咱們維護和管理。當咱們談論mounting時,咱們談論的是將虛擬組件轉換爲由React放置在DOM中的實際DOM元素的過程。瀏覽器

這對於諸如獲取數據來填充組件的事情很是有用。例如,假設咱們想使用咱們的活動跟蹤器來顯示github事件。只有當數據自己被渲染時,咱們纔想加載這些事件。框架

回想一下咱們在咱們的活動列表中定義了咱們的Content 組件socket

class Content extends React.Component {
  render() {
    const {activities} = this.props; // ES6 destructuring

    return (
      <div className="content">
        <div className="line"></div>

        {/* Timeline item */}
        {activities.map((activity) => (
          <ActivityItem
            activity={activity} />
        ))}

      </div>
    )
  }
}

讓咱們更新Content 組件,向github.com events api發出請求,並使用響應來顯示活動。 所以,咱們須要更新對象的state函數

就像咱們昨天作的那樣,咱們經過在構造函數中將this.state 設置爲一個對象來更新咱們的組件爲狀態fetch

class Content extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      activities: []
    }
  }

  // ...
}

如今,當組件自己準備裝載(或裝載以後)時,咱們將要發出一個HTTP請求。經過在咱們的組件中定義函數componentWillMount() (或componentDidMount()),React將在DOM中裝載該方法以前運行該方法。 這是咱們添加 GET 請求的完美的地方。

讓咱們更新content組件,並請求github api。 因爲咱們只想顯示一個小列表,咱們來看最新的四個活動。

咱們已經存儲了一個github數據的靜態JSON文件,咱們將直接從源碼(咱們將在幾天內使用AJAX請求)使用promises。 如今,讓咱們重點介紹如何使用新的數據實現更新組件:

class Content extends React.Component {
  // ...
  componentWillMount() {
    this.setState({activities: data});
  }
  // ...
}

請注意,咱們沒有從咱們的Content 組件更改任何內容,它正常工做了。

componentWillUpdate() / componentDidUpdate()

有時咱們會在更改實際呈現以前或以後更新咱們組件的一些數據。 例如,假設當組件的屬性更改時,咱們要調用一個函數來設置渲染或調用一個函數集。 componentWillUpdate() 方法是一個合理的鉤子來處理咱們的組件進行更改(只要咱們不調用this.setState() 來處理它,由於它會致使無限循環)。

因爲咱們真的不須要深刻處理這個問題,因此咱們不用擔憂在這裏設置一個例子,可是很高興知道它存在。 咱們使用的一個更常見的生命週期鉤子是componentWillReceiveProps() 鉤子。

componentWillReceiveProps()

當組件即將接收新的props時,React會調用一個方法。 這是當組件將要接收一組新的屬性時將被調用的第一種方法。 定義這種方法是尋找特定props 更新的好時機,由於它使咱們有機會計算更改並更新組件的內部狀態。

這時咱們能夠根據新屬性更新咱們的狀態。

這裏要注意的一點是,即便componentWillReceiveProps() 方法被調用,props 的值可能沒有更改。 老是 檢查prop值的變化是一個好主意。

例如,讓咱們添加一個_刷新_按鈕到咱們的活動列表,以便咱們的用戶能夠請求從新請求github事件api。

咱們將使用componentWillReceiveProps() 鉤子來要求組件從新加載它的數據。 因爲咱們的組件是有狀態的,咱們將要使用新數據刷新此狀態,所以咱們不能簡單地更新組件中的props 。 咱們可使用componentWillReceiveProps() 方法來_告訴_咱們要刷新的組件。

咱們在咱們的包含元素上添加一個按鈕,該元素傳遞一個requestRefresh布爾屬性來告訴Content組件刷新。

class Container extends React.Component {
  constructor(props) {
    super(props);

    this.state = {refreshing: false}
  }

  // Bound to the refresh button
  refresh() {
    this.setState({refreshing: true})
  }

  // Callback from the `Content` component
  onComponentRefresh() {
    this.setState({refreshing: false});
  }

  render() {
    const {refreshing} = this.state;
    return (
      <div className='notificationsFrame'>
        <div className='panel'>
          <Header title="Github activity" />
          {/* refreshing is the component's state */}
          <Content
            onComponentRefresh={this.onComponentRefresh.bind(this)}
            requestRefresh={refreshing}
            fetchData={fetchEvents} />
          {/* A container for styling */}
          <Footer>
            <button onClick={this.refresh.bind(this)}>
              <i className="fa fa-refresh" />
              Refresh
            </button>
          </Footer>
        </div>
      </div>
    )
  }
}

<Footer />

請注意,咱們有一個新元素顯示元素的子元素。 這是一種容許咱們圍繞一些內容添加CSS類的模式。

class Footer extends React.Component {
  render() {
    return (
      <div className='footer'>
        {this.props.children}
      </div>
    )
  }
}

使用這個新的proprequestRefresh prop),當咱們的state對象改變值時,咱們能夠更新activities

class Content extends React.Component {
  // ...
  componentWillReceiveProps(nextProps) {
    // Check to see if the requestRefresh prop has changed
    if (nextProps.requestRefresh !== this.props.requestRefresh) {
      this.setState({loading: true}, this.updateData);
    }
  }
  // ...
}

此演示使用JSON文件中的靜態數據,並在刷新時隨機挑選四個元素。 這被設置爲simulate刷新。

componentWillUnmount()

在組件卸載以前,React將調用componentWillUnmount() 回調。 這是處理咱們可能須要的任何清理事件的時候,例如清除超時,清除數據,斷開Websockets等。

例如,咱們上次工做使用咱們的時鐘組件,咱們設置一個超時時間被稱爲每秒鐘。 當組件準備卸載時,咱們但願確保咱們清除此超時,以便咱們的JavaScript不會繼續爲不存在的組件運行超時。

回想一下,咱們構建的 timer 組件看起來像這樣:

import React from 'react'

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = this.getTime();
  }

  componentDidMount() {
    this.setTimer();
  }

  setTimer() {
    this.timeout = setTimeout(this.updateClock.bind(this), 1000);
  }

  updateClock() {
    this.setState(this.getTime, this.setTimer);
  }

  getTime() {
    const currentTime = new Date();
    return {
      hours: currentTime.getHours(),
      minutes: currentTime.getMinutes(),
      seconds: currentTime.getSeconds(),
      ampm: currentTime.getHours() >= 12 ? 'pm' : 'am'
    }
  }

  // ...
  render() {

  }
}

export default Clock

當咱們的時鐘將被卸載時,咱們將要清除咱們在組件的setTimer() 函數中建立的超時。 添加componentWillUnmount() 函數負責這個必要的清理。

class Clock extends React.Component {
  // ...
  componentWillUnmount() {
    if (this.timeout) {
      clearTimeout(this.timeout);
    }
  }
  // ...
}

這些是咱們能夠在React框架中進行交互的一些生命週期鉤子。 當咱們構建咱們的應用程序時,咱們將會不少地使用這些應用,因此熟悉它們的方法是一個好主意,它們是如何存在,以及如何掛鉤組件的生命。

咱們在這篇文章中介紹了一個新的概念,咱們已經看到了:咱們在一個要從子組件調用到它的父組件上添加了一個回調。 在下一節中,咱們將介紹如何定義和記錄組件的prop API,以便在整個團隊和應用中共享組件時使用。

相關文章
相關標籤/搜索