本文轉載自:衆成翻譯
譯者: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> ) } }
使用這個新的prop
(requestRefresh
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,以便在整個團隊和應用中共享組件時使用。