組件的生命週期(Life Cycle)包含三個階段:掛載(Mounting)、更新(Updating)和卸載(Unmounting),在每一個階段都會有相應的回調方法(也叫鉤子)可供選擇,從而能更好的控制組件的行爲。php
在這個階段,組件會完成它的首次渲染,先執行初始化,再被掛載到真實的DOM中,其中依次調用的方法有constructor()、componentWillMount()、render()和componentDidMount()。除了render(),其餘三個方法都只會運行一次。json
1)constructor()服務器
在生命週期中,類的構造函數constructor()會率先被執行,用於初始化組件的狀態、接收外部傳遞進來的數據、綁定成員方法的this指向等工做。dom
2)componentWillMount()異步
componentWillMount()方法會運行在render()以前,它是渲染以前的回調函數。不過,因爲在這個方法中執行的任務都能提早到constructor()中,所以實際項目中不多會用到它。函數
3)render()post
render()是在定義組件時必須聲明的方法,它是一個無反作用的純函數,可根據組件的props和state獲得一個React元素、null或false等返回值,而且在render()方法中不能調用改變組件狀態的this.setState()方法。注意,將元素渲染到頁面DOM中的工做都由React負責,而不是render()方法。性能
4)componentDidMount()優化
componentDidMount()方法會運行在render()以後,它是渲染以後的回調函數。此時組件已被掛載到頁面中,能夠執行DOM相關的操做,例如異步讀取服務器中的數據並填充到組件中、調用jQuery代碼等。this
下面的組件沒有實際用途,僅僅是爲了演示四個回調函數,其中componentWillMount()和componentDidMount()都成功調用了this.setState()方法。
class Btn extends React.Component { constructor(props) { super(props); this.state = { name: props.name }; } componentWillMount() { this.setState({age: 28}); } render() { return <button>{this.state.name}</button>; } componentDidMount() { $.post("server.php", {id:1}, json => { this.setState({age: json.data.age}); }, "json"); } }
引發組件更新(即從新渲染)的方式有三種,第一種是由父組件向下傳遞props(即調用父組件的render()方法)引發的更新,依次會調用五個方法:componentWillReceiveProps()、shouldComponentUpdate()、componentWillUpdate()、render()和componentDidUpdate()。第二種是經過改變自身state(即調用this.setState()方法)引發的更新,會忽略componentWillReceiveProps()方法,只執行四個回調函數。第三種是經過組件的forceUpdate()方法強制更新,只有後三個回調函數會被執行。在下面的組件中,定義了更新階段的五個回調函數,而且點擊按鈕就會觸發強制更新。
class Btn extends React.Component { constructor(props) { super(props); this.state = { name: "strick" }; } dot() { this.setState({name: "freedom"}); this.forceUpdate(); //強制更新 } componentWillReceiveProps(nextProps) { } shouldComponentUpdate(nextProps, nextState) { return true; } componentWillUpdate(nextProps, nextState) { } render() { return <button onClick={this.dot.bind(this)}>{this.state.name}</button>; } componentDidUpdate(prevProps, prevState) { } }
1)componentWillReceiveProps()
componentWillReceiveProps()方法經常使用於執行props更新後的邏輯,只有第一種更新方式纔會調用它,該方法能接收一個名爲nextProps的參數,表示父組件傳遞進來的新的props。當須要經過this.setState()方法將nextProps中的數據同步到內部狀態時,要先比較nextProps和this.props中的值是否相同,再決定是否執行同步。因爲在componentWillReceiveProps()中能調用this.setState()方法,所以爲了不進入一個死循環,在調用this.setState()方法更新組件時就不會觸發它。
2)shouldComponentUpdate()
shouldComponentUpdate()用於決定是否繼續組件的更新,它能接收2個參數:nextProps和nextState,分別表示新的props和state,經過比較nextProps、nextState和組件當前的this.props、this.state能得出一個布爾類型的返回結果。當返回結果爲false時,組件會中止更新,後續的componentWillUpdate()、render()和componentDidUpdate()也不會被執行。將這個方法使用恰當的話,能減小冗餘的渲染,優化組件的性能。
3)componentWillUpdate()和componentDidUpdate()
componentWillUpdate()和componentDidUpdate()分別運行在render()以前和以後,它們都能接收2個參數,前者提供更新後的props和state,後者提供更新前的props和state。在componentWillUpdate()中,不能調用this.setState()方法,以避免發生沒必要要的死循環。
當組件在從DOM中被卸載以前,會觸發一個無參數的componentWillUnmount()方法。在該方法內適合作些清理的工做,例如清除定時器、移除多餘的DOM元素等。下面演示了處理卸載的過程,限於篇幅省略了組件的構造函數和render()方法,只給出了關鍵代碼。
class Btn extends React.Component { componentWillUnmount() { clearInterval(timeout); } } var container = document.getElementById("container"); ReactDOM.render(<Btn>提交</Btn>, container); ReactDOM.unmountComponentAtNode(container); //移除DOM中的組件
接下來用一張總的流程圖(如圖5所示)來講明生命週期各個方法之間的關係,灰底的方法表示在其內部能調用this.setState()方法。
圖5 組件生命週期流程圖