四個階段
- 初始化
- 執行中
- 銷燬
- 錯誤處理(16.3以後)
- 初始化
- constructor
- static getDerivedStateFromProps()
- componentWillMount() / UNSAFE_componentWillMount()
- render()
- componentDidMount()
- 更新
props
或state
的改變可能會引起元件的更新,元件重新渲染的過程中會呼叫以下方法:- componentWillReceiveProps() / UNSAFE_componentWillReceiveProps()
- static getDerivedStateFromProps()
- shouldComponentUpdate()
- componentWillUpdate() / UNSAFE_componentWillUpdate()
- render()
- getSnapshotBeforeUpdate()
- componentDidUpdate()
- 銷燬
- componentWillUnmount()
- 錯誤處理
- componentDidCatch()
各個生命週期詳解
(1)constructor
- React元件的建構函式在掛在之前被呼叫。
- 呼叫
super(props)
,用來將父元件傳來的props
繫結到這個類中,使用this.props
將會得到。 constructor
中應當做些初始化的動作,如:初始化state
,將事件處理函式繫結到類例項上,但也不要使用setState()
。
使用場景:- 初始化state資料
- 定義函式修改this指向
constructor(props) { super(props); this.state = { isLiked: props.isLiked }; this.handleFun=this.handleFun.bind(this) }
(2)static getDerivedStateFromProps(nextProps, prevState)
React 16.3 的版本中 getDerivedStateFromProps 的觸發範圍是和 16.4^ 是不同的,主要區別是在 setState
和 forceUpdate
時會不會觸發,具體可以看這個生命全週期圖 。
使用場景:
- 無條件的根據 prop 來更新內部 state,也就是隻要有傳入 prop 值, 就更新 state
- 只有 prop 值和 state 值不同時才更新 state 值。
Class ColorPicker extends React.Component {
state = {
color: '#000000'
}
static getDerivedStateFromProps (props, state) {
if (props.color !== state.color) {
return {
color: props.color
}
}
return null
}
... // 選擇顏色方法
render () {
.... // 顯示顏色和選擇顏色操作
}
}
純在問題:
現在我們可以這個顏色選擇器來選擇顏色,同時我們能傳入一個顏色值並顯示。如果我們傳入一個顏色值後,再使用元件內部的選擇顏色方法,我們會發現顏色不會變化,一直是傳入的顏色值。
這是使用這個生命週期的一個常見 bug。為什麼會發生這個 bug 呢?在開頭有說到,在 React 16.4^ 的版本中 setState
和 forceUpdate
也會觸發這個生命週期,所以內部 state 變化後,又會走 getDerivedStateFromProps 方法,並把 state 值更新為傳入的 prop。
Class ColorPicker extends React.Component {
state = {
color: '#000000',
prevPropColor: ''
}
static getDerivedStateFromProps (props, state) {
if (props.color !== state.prevPropColor) {
return {
color: props.color
prevPropColor: props.color
}
}
return null
}
... // 選擇顏色方法
render () {
.... // 顯示顏色和選擇顏色操作
}
}
注意點:
- 因為這個生命週期是靜態方法,同時要保持它是純函式,不要產生副作用。
- 在使用此生命週期時,要注意把傳入的 prop 值和之前傳入的 prop 進行比較(這個 prop 值最好有唯一性,或者使用一個唯一性的 prop 值來專門比較)。
- 不使用 getDerivedStateFromProps,可以改成元件保持完全不可控模式,通過初始值和 key 值來實現 prop 改變 state 的情景。
(3) componentWillMount() / UNSAFE_componentWillMount()
componentWillMount()
將在React未來版本(官方說法 17.0)中被棄用。UNSAFE_componentWillMount()
在元件掛載前被呼叫,在這個方法中呼叫setState()
不會起作用,是由於他在render()
前被呼叫。
(4)render()
當他被呼叫時,他將計算this.props
和this.state
,並返回以下一種型別:
- React元素。通過jsx建立,既可以是dom元素,也可以是使用者自定義的元件。
- 字串或數字。他們將會以文字節點形式渲染到dom中。
- Portals。react 16版本中提出的新的解決方案,可以使元件脫離父元件層級直接掛載在DOM樹的任何位置。
- null,什麼也不渲染
- 布林值。也是什麼都不渲染。
注意:返回null,false,ReactDOM.findDOMNode(this)將會返回null,什麼都不會渲染
render()
方法必須是一個純函式,他不應該改變state
,也不能直接和瀏覽器進行互動,應該將事件放在其他生命週期函式中。
如果shouldComponentUpdate()
返回false
,render()
不會被呼叫。
(5)componentDidMount
元件被裝配後立即呼叫。
應用場景:
- 通常在這裡進行ajax請求
- 初始化第三方的dom庫
(6)componentWillReceiveProps()/UNSAFE_componentWillReceiveProps(nextProps)
建議使用getDerivedStateFromProps
函式代替
- 當元件掛載後,接收到新的
props
後會被呼叫 - 如果需要更新
state
來響應props
的更改,則可以進行this.props
和nextProps
的比較,並在此方法中使用this.setState()
。 - 如果父元件會讓這個元件重新渲染,即使
props
沒有改變,也會呼叫這個方法。 - React不會在元件初始化props時呼叫這個方法。呼叫
this.setState
也不會觸發。
(7) shouldComponentUpdate(nextProps, nextState)
- 渲染新的
props
或state
前,shouldComponentUpdate
會被呼叫預設為true
。 - 這個方法不會在初始化時被呼叫,也不會在
forceUpdate()
時被呼叫。返回false
不會阻止子元件在state
更改時重新渲染。 - 如果
shouldComponentUpdate()
返回false
,componentWillUpdate
,render
和componentDidUpdate
不會被呼叫。官方並不建議在
shouldComponentUpdate()
中進行深度查詢或使用JSON.stringify()
,他效率非常低,並且損傷效能
//下次的props和state資料
shouldComponentUpdate(nextProps,nextState){
if(nextProps.data==this.props.data){
return false
}
return true
}
(8) UNSAFE_componentWillUpdate(nextProps, nextState)
渲染新的state
或props
時,UNSAFE_componentWillUpdate
會被呼叫.
將此作為在更新發生之前進行準備的機會。這個方法不會在初始化時被呼叫
不能在這裡使用this.setState(),也不能做會觸發檢視更新的操作。如果需要更新state
或props
,呼叫getDerivedStateFromProps
(9) getSnapshotBeforeUpdate()
render()
後的輸出被渲染到DOM之前被呼叫。
- 它使您的元件能夠在它們被潛在更改之前捕獲當前值(如滾動位置)。
- 這個生命週期返回的任何值都將作為引數傳遞給componentDidUpdate()。
(10) componentDidUpdate(prevProps, prevState, snapshot)
在更新發生後立即呼叫componentDidUpdate()
。
此方法不用於初始渲染。當元件更新時,將此作為一個機會來操作DOM。只要您將當前的props與以前的props進行比較(例如,如果props沒有改變,則可能不需要網路請求),這也是做網路請求的好地方。
如果元件實現getSnapshotBeforeUpdate()
生命週期,則它返回的值將作為第三個“快照”引數傳遞給componentDidUpdate()
。否則,這個引數是undefined
。
(11) componentWillUnmount()
在元件被解除安裝並銷燬之前立即被呼叫。
在此方法中執行任何必要的清理,例如使定時器無效,取消網路請求或清理在componentDidMount
中建立的任何監聽。
(12) componentDidCatch(error, info)
錯誤邊界是React元件,可以在其子元件樹中的任何位置捕獲JavaScript錯誤,記錄這些錯誤並顯示回退UI,而不是崩潰的元件樹。錯誤邊界在渲染期間,生命週期方法以及整個樹下的建構函式中捕獲錯誤。
如果類元件定義了此生命週期方法,則它將成錯誤邊界。在它中呼叫setState()
可以讓你在下面的樹中捕獲未處理的JavaScript錯誤,並顯示一個後備UI。只能使用錯誤邊界從意外異常中恢復; 不要試圖將它們用於控制流程。
錯誤邊界只會捕獲樹中下面元件中的錯誤。錯誤邊界本身不能捕獲錯誤
PureComponent
PureComponent
裡如果接收到的新屬性或者是更改後的狀態和原屬性、原狀態相同的話,就不會去重新render了
在裡面也可以使用shouldComponentUpdate
,,而且。
是否重新渲染以shouldComponentUpdate
的返回值為最終的決定因素。
import React, { PureComponent } from 'react'
class YourComponent extends PureComponent {
……
}
ref
對元件真正例項的引用,其實就是ReactDOM.render()
返回的元件例項,ref
可以掛載到元件上也可以是dom元素上。
- 掛到元件(
class
宣告的元件)上的ref表示對元件例項的引用。不能在函式式元件上使用 ref 屬性,因為它們沒有例項: - 掛載到dom元素上時表示具體的dom元素節點。
import React, { Component, createRef } from 'react'
import ReactDOM from 'react-dom'
class App extends Component {
constructor() {
super()
// 建立inputRef
this.inputRef = createRef()
}
componentDidMount () {
console.log(this.inputRef.current) // <input type="text">
}
render () {
return (
<div>
{/* 關聯ref和dom */}
<input type="text" ref={this.inputRef} />
</div>
)
}
}
ReactDOM.render(
<App/>,
document.getElementById('root')