組件的生命周期方法分以下三個(gè)階段。
Mounting
當(dāng)創(chuàng)建組件的實(shí)例并將其插入到DOM中時(shí),將調(diào)用這些方法:
constructor()
componentWillMount()
render()
componentDidMount()
Updating
更新可能是props或state的改變引起的。 當(dāng)重新渲染組件時(shí),將調(diào)用這些方法:
componentWillReceiveProps()
shouldComponentUpdate()
componentWillUpdate()
render()
componentDidUpdate()
Unmounting
當(dāng)組件從dom中移除時(shí)調(diào)用:
componentWillUnmount()
找來一張圖:
以下詳細(xì)講解下每個(gè)方法(翻譯來的)。
render()
render()方法是必需的。調(diào)用時(shí),應(yīng)該檢查this.props和this.state并返回一個(gè)React元素。 例如<div />或您自己定義的另一個(gè)復(fù)合組件。
您也可以返回null
或false
表示您不希望任何呈現(xiàn)。 返回null
或false
時(shí),ReactDOM.findDOMNode(this)將返回null
。
render()函數(shù)應(yīng)該是純函數(shù),這意味著它不會(huì)修改組件狀態(tài),每次調(diào)用它都會(huì)返回相同的結(jié)果,并且它不會(huì)直接與瀏覽器交互。 如果需要與瀏覽器交互,請(qǐng)?jiān)赾omponentDidMount()或其他生命周期方法中執(zhí)行工作。 保持render()純粹使組件更容易思考。
如果shouldComponentUpdate()返回false,則不會(huì)調(diào)用render()。
constructor(props)
組件構(gòu)造函數(shù)會(huì)在組件裝載到頁面之前調(diào)用。在實(shí)現(xiàn)React.Component子類的構(gòu)造函數(shù)時(shí),您應(yīng)該在任何其他語句之前調(diào)用super(props)
。 否則,this.props將在構(gòu)造函數(shù)中未定義,這可能會(huì)導(dǎo)致錯(cuò)誤。
構(gòu)造函數(shù)是初始化狀態(tài)的正確位置。 如果不初始化狀態(tài)并且不綁定方法,則不需要為您的React組件實(shí)現(xiàn)一個(gè)構(gòu)造函數(shù)。
可以根據(jù)props來初始化狀態(tài)。 這是一個(gè)有效的React.Component子類構(gòu)造函數(shù)的示例:
constructor(props) {
super(props);
this.state = {
color: props.initialColor
};
}
小心這種模式,因?yàn)闋顟B(tài)不會(huì)隨著任何props更新而更新。 你通常不想將props同步到state,而是要提升狀態(tài)。如果您通過使用props更新狀態(tài),您可能還需要實(shí)現(xiàn)componentWillReceiveProps(nextProps)來保持狀態(tài)與其最新狀態(tài)。 但是提升狀態(tài)往往比較容易,而且不容易出錯(cuò)。
componentWillMount()
在元素裝載發(fā)生之前會(huì)調(diào)用componentWillMount()。
避免在此方法中引入任何副作用或訂閱。
它在render()之前被調(diào)用,因此在該方法中同步設(shè)置狀態(tài)不會(huì)觸發(fā)重新呈現(xiàn)。 這是在服務(wù)器渲染上調(diào)用的唯一生命周期鉤子。 一般來說,建議使用constructor()。
componentDidMount()
在元素裝載發(fā)生之后會(huì)調(diào)用componentDidMount()。
DOM節(jié)點(diǎn)的初始化應(yīng)該在這里。 如果需要從遠(yuǎn)程端點(diǎn)加載數(shù)據(jù),這是實(shí)例化網(wǎng)絡(luò)請(qǐng)求的好地方。 此方法中的設(shè)置狀態(tài)將觸發(fā)重新渲染。
componentWillReceiveProps(nextProps)
當(dāng)組件接收到一個(gè)新的props時(shí)該方法觸發(fā). 如果需要更新狀態(tài)以響應(yīng)更改(例如,要重置它),則可以比較this.props和nextProps,并使用此方法中的this.setState()執(zhí)行狀態(tài)轉(zhuǎn)換。
請(qǐng)注意,即使props沒有改變,React也可以調(diào)用此方法,因此如果只想處理更改,請(qǐng)確保比較當(dāng)前值和下一個(gè)值。 當(dāng)父組件使您的組件重新呈現(xiàn)時(shí),可能會(huì)發(fā)生這種情況。
在裝載過程中,React不會(huì)使用初始props調(diào)用componentWillReceiveProps。 只會(huì)在某些組件的props更新時(shí)才會(huì)調(diào)用此方法。 調(diào)用this.setState通常不會(huì)觸發(fā)componentWillReceiveProps。
shouldComponentUpdate(nextProps, nextState)
使用shouldComponentUpdate()讓React知道組件的輸出是否不受當(dāng)前state或props的更改的影響。默認(rèn)行為是在每個(gè)狀態(tài)更改時(shí)重新呈現(xiàn),而在絕大多數(shù)情況下,您應(yīng)該依賴于默認(rèn)行為。
在接收到新的props或state時(shí),將在渲染之前調(diào)用shouldComponentUpdate()。默認(rèn)為true。
對(duì)于初始渲染,或者當(dāng)使用forceUpdate()時(shí),不調(diào)用此方法。
返回false不會(huì)阻止子組件在狀態(tài)更改時(shí)重新渲染。
目前,如果shouldComponentUpdate()返回false,那么將不會(huì)調(diào)用componentWillUpdate(),render()和componentDidUpdate()。請(qǐng)注意,在將來,React可以將shouldComponentUpdate()作為一個(gè)提示而不是一個(gè)strict指令,并返回false仍然可能導(dǎo)致組件的重新呈現(xiàn)。
如果在分析后確定特定組件較慢,則可以將其更改為繼承自實(shí)現(xiàn)shouldComponentUpdate()的React.PureComponent
,對(duì)props和state進(jìn)行淺比較。如果您有信心要手動(dòng)編寫,可以將this.props與nextProps和this.state與nextState進(jìn)行比較,并返回false以告知React可以跳過更新。
componentWillUpdate(nextProps, nextState)
會(huì)在render之前觸發(fā),一個(gè)新的props和state會(huì)被做為參數(shù)傳進(jìn)來 。使用此作為在更新發(fā)生之前進(jìn)行準(zhǔn)備的機(jī)會(huì)。 初始化渲染不會(huì)調(diào)用此方法。
請(qǐng)注意,您不能在此處調(diào)用this.setState()。 如果需要更新狀態(tài)以響應(yīng)更改,請(qǐng)改用componentWillReceiveProps()。
如果shouldComponentUpdate()返回false,則不會(huì)調(diào)用componentWillUpdate()。
componentDidUpdate(prevProps, prevState)
會(huì)在更新發(fā)生后立即執(zhí)行. 初始化渲染不會(huì)調(diào)用此方法。
當(dāng)組件更新時(shí),使用它作為在DOM上操作的機(jī)會(huì)。 只要您將當(dāng)前props與以前的props進(jìn)行比較。
這也是網(wǎng)絡(luò)請(qǐng)求的好地方(如果props沒有改變,則網(wǎng)絡(luò)請(qǐng)求可能不是必需的)。
componentWillUnmount()
在組件被卸載并銷毀之前,會(huì)立即調(diào)用此方法。 在此方法中執(zhí)行任何必要的清理,例如使定時(shí)器無效,取消網(wǎng)絡(luò)請(qǐng)求或清除DOM元素
(在componentDidMount中創(chuàng)建的任何DOM元素)。
setState(updater, [callback])
setState()將對(duì)組件狀態(tài)的更改插入隊(duì)列,并告訴React,該組件及其子組件需要更新狀態(tài)重新呈現(xiàn)。這是用于更新用戶界面以響應(yīng)事件處理程序和服務(wù)器響應(yīng)的主要方法。
將setState()作為請(qǐng)求而不是立即命令來更新組件。為了更好的感知性能,React可能會(huì)延遲它,然后在單次通過中更新多個(gè)組件。 React不能保證立即應(yīng)用狀態(tài)更改。
setState()并不總是立即更新組件。它可能會(huì)批量或延遲更新直。這使得在調(diào)用setState()之后立即讀取this.state是一個(gè)潛在的陷阱。最好的方法是使用componentDidUpdate或setState回調(diào)(setState(updater,callback)),其中的任何一個(gè)都會(huì)在應(yīng)用更新后都被觸發(fā)。
setState()將永遠(yuǎn)導(dǎo)致重新渲染,除非shouldComponentUpdate()返回false。
第一個(gè)參數(shù)是具有簽名的更新功能:
(prevState,props)=> stateChange
prevState是對(duì)以前狀態(tài)的引用。不應(yīng)該直接突變。相反,應(yīng)該根據(jù)prevState和props的輸入構(gòu)建一個(gè)新對(duì)象來表示更改。例如,假設(shè)我們想通過props.step來增加狀態(tài)值:
this.setState((prevState,props)=> {
return {counter:prevState.counter + props.step};
});
updater功能接收到的prevState和props都保證是最新的。更新器的輸出與prevState進(jìn)行了淺層合并。
setState()的第二個(gè)參數(shù)是一個(gè)可選的回調(diào)函數(shù),它將在setState完成并且重新呈現(xiàn)該組件后執(zhí)行。通常我們建議使用componentDidUpdate()作為這樣的邏輯。
您可以選擇將一個(gè)對(duì)象作為第一個(gè)參數(shù)傳遞給setState()而不是一個(gè)函數(shù):
setState(stateChange,[callback])
這將執(zhí)行stateChange的淺合并到新的狀態(tài),例如調(diào)整購物車商品數(shù)量:
this.setState({quantity:2})
這種形式的setState()也是異步的,同一周期中的多個(gè)調(diào)用可以被批處理在一起。例如,如果您嘗試在同一周期內(nèi)多次增加項(xiàng)目數(shù)量,則會(huì)導(dǎo)致相當(dāng)于:
Object.assign(
previousState,
{quantity:state.quantity + 1},
{quantity:state.quantity + 1},
...
)
后續(xù)呼叫將覆蓋同一周期中先前呼叫的值,因此數(shù)量只會(huì)增加一次。如果下一個(gè)狀態(tài)取決于以前的狀態(tài),我們建議使用updater函數(shù)形式:
this.setState((prevState)=> {
return {counter:prevState.quantity + 1};
});
forceUpdate (callback)
默認(rèn)情況下,當(dāng)您的組件的state或props更改時(shí),您的組件將重新呈現(xiàn)。如果您的render()方法依賴于某些其他數(shù)據(jù),您可以通過調(diào)用forceUpdate()來告訴React該組件需要重新呈現(xiàn)。
調(diào)用forceUpdate()將導(dǎo)致在組件上調(diào)用render(),跳過shouldComponentUpdate()。這將觸發(fā)子組件的正常生命周期方法,包括每個(gè)子組件的shouldComponentUpdate()方法。如果標(biāo)記更改,則React仍將僅更新DOM。
通常你應(yīng)該盡量避免使用forceUpdate(),只能從render.()中的this.props和this.state讀取。