React生命周期函數(shù)深入全面介紹
1. 注意
函數(shù)組件無生命周期,生命周期只有類組件才擁有。
2. 圖解
完整的生命周期主要為三個(gè)部分,分別為掛載時(shí)、更新時(shí)和卸載時(shí),如下圖所示:

3. 生命周期函數(shù)
3.1 constructor構(gòu)造函數(shù)
描述:
React 組件的構(gòu)造函數(shù)在掛載之前被調(diào)用。在實(shí)現(xiàn) React.Component 構(gòu)造函數(shù)時(shí),需要先在添加其它內(nèi)容前,調(diào)用 super(props),用來將父組件傳來的 props 綁定到繼承類中。
構(gòu)造函數(shù)它只執(zhí)行1次,可以進(jìn)行數(shù)據(jù)初始化操作,因?yàn)樗撬械纳芷谥械?個(gè)被執(zhí)行的方法,但是不太建議在此方法中進(jìn)行網(wǎng)絡(luò)請(qǐng)求。
父組件的構(gòu)造方法先執(zhí)行,子組件的構(gòu)造方法后執(zhí)行。
語法:
constructor(props) {
// 如果你在定義組件中有定義構(gòu)造函數(shù),則一定要調(diào)用super方法來調(diào)用父類的構(gòu)造函數(shù)
super(props)
// todo …
}
3.2 static getDerivedStateFromProps(nextProps, prevState)方法
描述:
此方法在構(gòu)造函數(shù)方法之后,Render 方法之前被調(diào)用,并且在初始掛載及后續(xù)更新時(shí)都會(huì)被調(diào)用。它應(yīng)返回一個(gè)對(duì)象來更新 state,如果返回 null 則不更新任何內(nèi)容。
此方法適用于罕見的用例,即當(dāng)前組件的 state 的值在任何時(shí)候都取決于 props 傳入。
語法:
state = {
num: 0
};
render() {
return <div>當(dāng)前的num是{this.state.num}</div>;
}
// 從props中獲取數(shù)據(jù),綁定到當(dāng)前的這個(gè)組件中的state
// nextProps 父組件傳遞過來的整個(gè)props對(duì)象,即當(dāng)前最新的props數(shù)據(jù)
// prevState 當(dāng)前組件中的狀態(tài)對(duì)象state,即當(dāng)前最新的state數(shù)據(jù),但暫時(shí)不包含返回值中要對(duì)state修改的值
static getDerivedStateFromProps(nextProps, prevState) {
// 不需要更新當(dāng)前state
return null
}注意:
- 此方法會(huì)執(zhí)行 n 次
- 此方法它是一個(gè)靜態(tài)方法,靜態(tài)方法中不能使用 this
- 使用此方法一定要先定義好 state,否則報(bào)錯(cuò)
- 此方法必須要有返回值,
{}|null,如果返回為對(duì)象,則會(huì)對(duì) state 中數(shù)據(jù)進(jìn)行操作,返回的對(duì)象屬性如果在 state 中沒有則添加,有則修改;如果返回為 null,則不會(huì)對(duì) state 進(jìn)行任何操作
getDerivedStateFromProps 在父子組件中執(zhí)行的先后順序,及 nextProps, prevState 的使用:
import React, { Component } from 'react'
class Child extends Component {
constructor(props) {
super(props)
this.state = { num: 100 }
console.log('child --- constructor')
}
// 快捷輸入 gdsfp
static getDerivedStateFromProps(nextProps, nextState) {
console.log('child --- getDerivedStateFromProps')
// nextState: 當(dāng)前最新的state數(shù)據(jù),暫時(shí)不包含你返回值中要對(duì)state修改的值
console.log(nextProps, nextState)
return { name: '張三' }
}
render() {
return (
<div>
<h3>Child組件</h3>
</div>
)
}
}
class App extends Component {
constructor(props) {
super(props)
this.state = { age: 1 }
// 父組件先執(zhí)行后子組件執(zhí)行此方法 app -> child
console.log('App --- constructor')
}
static getDerivedStateFromProps(nextProps, nextState) {
console.log('App --- getDerivedStateFromProps')
return null
}
render() {
return (
<div>
<Child name='李四' />
</div>
)
}
}
export default App
注意:由于這個(gè)方法會(huì)執(zhí)行 n 次,所以不建議在這個(gè)方法中發(fā)送網(wǎng)絡(luò)請(qǐng)求,容易造成死循環(huán)。如果想要在這個(gè)方法中發(fā)送網(wǎng)絡(luò)請(qǐng)求,則一定要確保不要觸發(fā)這個(gè)方法再次執(zhí)行(即父組件不發(fā)送新的 props 或修改 props ,不修改 state ,不強(qiáng)制更新視圖)
小案例:
描述:
子組件將 state 中的數(shù)據(jù)修改為 nextProps 中的值,并且點(diǎn)擊增加按鈕能夠觸發(fā)后續(xù)對(duì)值的修改。
實(shí)現(xiàn):
import React, { Component } from 'react'
class Child extends Component {
constructor(props) {
super(props)
this.state = { name: '張三' }
}
// 快捷輸入 gdsfp
static getDerivedStateFromProps(nextProps, nextState) {
console.log('child --- getDerivedStateFromProps')
// 如果你想用此方法,把props中的屬性數(shù)據(jù),追加到state中,后續(xù)能修改,則這樣的操作,你要確保只執(zhí)行1次
// 這種方式只能接收到父組件第一次值過來的值(10),點(diǎn)擊按鈕子組件age并不會(huì)增加
// 這是因?yàn)槊看吸c(diǎn)擊增加按鈕都會(huì)觸發(fā)當(dāng)前函數(shù),將state中的age修改為nextProps
// return nextProps // 這種方式不會(huì)觸發(fā)點(diǎn)擊按鈕增加age值
if (nextState.flag != 1) {
return { ...nextProps, flag: 1 }
}
return null
}
render() {
let { age } = this.state
return (
<div>
<h3>Child組件 -- {age}</h3>
<button
onClick={() => {
this.setState(state => ({ age: state.age + 1 }))
}}
>
++age++
</button>
</div>
)
}
}
class App extends Component {
constructor(props) {
super(props)
this.state = { age: 1 }
}
render() {
return (
<div>
<Child age={10} />
</div>
)
}
}
export default App
3.3 掛載時(shí)和更新時(shí)的生命周期函數(shù)執(zhí)行順序
掛載時(shí)生命周期函數(shù)介紹:
- constructor(props)
React組件的構(gòu)造函數(shù)在掛載之前被調(diào)用。在實(shí)現(xiàn)React.Component構(gòu)造函數(shù)時(shí),需要先在添加其它內(nèi)容前,調(diào)用super(props),用來將父組件傳來的props綁定到繼承類中。只調(diào)用一次。
- static getDerivedStateFromProps(nextProps, prevState)
此方法是react16.3之后新增,會(huì)在調(diào)用 render 方法之前調(diào)用,并且在初始掛載及后續(xù)更新時(shí)都會(huì)被調(diào)用。它應(yīng)返回一個(gè)對(duì)象來更新 state,如果返回 null 則不更新任何內(nèi)容。
此方法適用于罕見的用例,即當(dāng)前組件的 state 的值在任何時(shí)候都取決于 props傳入。
- render()
render()方法是必需的,它主要負(fù)責(zé)組件的渲染,會(huì)被重復(fù)調(diào)用若干次
- componentDidMount
它會(huì)在組件掛載后(插入 DOM 樹中)立即調(diào)用。依賴于 DOM 節(jié)點(diǎn)的初始化應(yīng)該放在這里。如需通過網(wǎng)絡(luò)請(qǐng)求獲取數(shù)據(jù),此處是實(shí)例化請(qǐng)求的好地方。
- shouldComponentUpdate(nextProps, nextState)
此函數(shù)將放在下文單獨(dú)講解。
- getSnapshotBeforeUpdate(prevProps, prevState)
在最近一次渲染輸出(提交到 DOM 節(jié)點(diǎn))之前調(diào)用。它使得組件能在發(fā)生更改之前從 DOM 中捕獲一些信息,此生命周期的任何返回值將作為參數(shù)傳遞給 componentDidUpdate()
- componentDidUpdate(prevProps, prevState, snapshot)
會(huì)在數(shù)據(jù)更新后被立即調(diào)用。首次渲染不會(huì)執(zhí)行此方法。
import React, { Component } from 'react'
class Child extends Component {
constructor(props) {
super(props)
this.state = { name: '張三' }
console.log('child --- constructor')
}
// 快捷輸入 gdsfp
static getDerivedStateFromProps(nextProps, nextState) {
console.log('child --- getDerivedStateFromProps')
if (nextState.flag != 1) {
return { ...nextProps, flag: 1 }
}
return null
}
// 它只執(zhí)行1次
// 虛擬dom掛載到真實(shí)的頁面點(diǎn)中完成,在此進(jìn)行dom操作
// 在此可以進(jìn)行網(wǎng)絡(luò)請(qǐng)求
componentDidMount() {
console.log('child -- componentDidMount')
}
// ------------- 更新時(shí)
// prevProps 修改之前的props數(shù)據(jù)
// prevState 修改之前的state數(shù)據(jù)
// 此方法要有一個(gè)返回值,且如果有此方法,則必須要有componentDidUpdate
// 此方法的返回值,會(huì)在componentDidUpdate參數(shù)3中接受
getSnapshotBeforeUpdate(prevProps, prevState) {
console.log('child --- getSnapshotBeforeUpdate')
return 100
}
// 數(shù)據(jù)更新完畢后執(zhí)行
componentDidUpdate(prevProps, prevState, snapshot) {
console.log('child --- componentDidUpdate', snapshot)
}
render() {
console.log('child -- render')
let { age } = this.state
return (
<div>
<h3>Child組件 -- {age}</h3>
<button
onClick={() => {
this.setState(state => ({ age: state.age + 1 }))
}}
>
++ Child -- age ++
</button>
</div>
)
}
}
class App extends Component {
constructor(props) {
super(props)
this.state = { age: 1 }
console.log('App --- constructor')
}
static getDerivedStateFromProps(nextProps, nextState) {
console.log('App --- getDerivedStateFromProps')
return null
}
componentDidMount() {
console.log('App -- componentDidMount')
}
getSnapshotBeforeUpdate(prevProps, prevState) {
console.log('App --- getSnapshotBeforeUpdate')
return 200
}
// 數(shù)據(jù)更新完畢后執(zhí)行
componentDidUpdate(prevProps, prevState, snapshot) {
console.log('App --- componentDidUpdate', snapshot)
}
render() {
let { age } = this.state
console.log('App -- render')
return (
<div>
<h3>App組件 -- {age}</h3>
<Child age={age} />
<button
onClick={() => {
this.setState(state => ({ age: state.age + 1 }))
}}
>
++ App -- age ++
</button>
</div>
)
}
}
export default App掛載時(shí):

更新時(shí):

3.4 componentWillUnmount函數(shù)的使用
描述:
componentWillUnmount() 會(huì)在組件卸載及銷毀之前直接調(diào)用。在此方法中執(zhí)行必要的清理操作。
使用:
import React, { Component } from 'react'
class Child extends Component {
constructor(props) {
super(props)
this.state = { name: '張三' }
}
// 快捷輸入 gdsfp
static getDerivedStateFromProps(nextProps, nextState) {
if (nextState.flag != 1) {
return { ...nextProps, flag: 1 }
}
return null
}
// 銷毀組件時(shí)執(zhí)行
componentWillUnmount() {
console.log('child --- componentWillUnmount')
}
render() {
let { age } = this.state
return (
<div>
<h3>Child組件 -- {age}</h3>
<button
onClick={() => {
this.setState(state => ({ age: state.age + 1 }))
}}
>
++ Child -- age ++
</button>
</div>
)
}
}
class App extends Component {
constructor(props) {
super(props)
this.state = { age: 1 }
}
getSnapshotBeforeUpdate(prevProps, prevState) {
console.log('App --- getSnapshotBeforeUpdate')
return 200
}
// 數(shù)據(jù)更新完畢后執(zhí)行
componentDidUpdate(prevProps, prevState, snapshot) {
console.log('App --- componentDidUpdate', snapshot)
}
render() {
let { age } = this.state
return (
<div>
<h3>App組件 -- {age}</h3>
{/* age大于1時(shí)銷毀子組件 */}
{age > 1 ? null : <Child age={age} />}
<button
onClick={() => {
this.setState(state => ({ age: state.age + 1 }))
}}
>
++ App -- age ++
</button>
</div>
)
}
}
export default App
3.5 shouldComponentUpdate優(yōu)化渲染方案
描述:
React 的更新機(jī)制導(dǎo)致,即使子組件未發(fā)生更新,只要父組件中的 state 改變,當(dāng)前父組件及其所有子組件都會(huì)重新渲染,這樣做雖然很高效,但會(huì)造成不少性能損耗,那么該如何避免呢?
當(dāng) props 或 state 發(fā)生變化時(shí),shouldComponentUpdate() 會(huì)在渲染執(zhí)行之前被調(diào)用。返回值默認(rèn)為 true 則組件繼續(xù)渲染,為 false 則當(dāng)前組件不會(huì)渲染。首次渲染或使用 forceUpdate() 時(shí)不會(huì)調(diào)用該方法。此方法僅作為性能優(yōu)化的方式而存在。你也可以考慮使用內(nèi)置的 PureComponent 組件,而不是手動(dòng)編寫 shouldComponentUpdate()。
PureComponent 會(huì)對(duì) props 和 state 進(jìn)行淺層比較,并減少了跳過必要更新的可能性。 PureComponent 它可以對(duì)于組件無效渲染起到一定的優(yōu)化,但是它只能針對(duì)于props中值為基本類型。
所以我們還可以使用生命周期中提供的優(yōu)化方案,使用 shouldComponentUpdate 減少無效渲染次數(shù)。
語法:
shouldComponentUpdate(nextProps, nextState) {
// 判斷是否需要被渲染,如果需要?jiǎng)t返回true,否則返回false
if (nextProps.b === this.props.b) {
return false;
} else {
return true;
}
}
// 簡(jiǎn)化方法:只需要將類組件的繼承關(guān)系改成繼承`PureComponent`即可,這樣一來,框架會(huì)自動(dòng)判斷值是否有變化進(jìn)一步?jīng)Q定組件是否需要被渲染。
import React, { PureComponent } from "react";
class Cmp extends PureComponent {
render() {
console.log("Cmp被渲染了");
return <div>父親傳遞過來的值b為:{this.props.b}</div>;
}
}
export default Cmp使用:
import React, { Component, PureComponent } from 'react'
// PureComponent 它可以對(duì)于組件無效渲染起到一定的優(yōu)化,但是它只能針對(duì)于props中值為基本類型
// 可以使用生命周期中提供的優(yōu)化方案,提升無效渲染次數(shù)
// class Child extends PureComponent {
class Child extends Component {
// 此方法,用于組件重復(fù)渲染的優(yōu)化方法,它不是必須要用的
// 此方法必須要有一個(gè)boolean返回值
// 此方法只有在更新時(shí)才會(huì)觸發(fā)
// true 則繼續(xù)向下渲染 render
// false 表示當(dāng)前不會(huì)繼續(xù)渲染,從而減少無用渲染,提升性能
// nextProps 最新的props數(shù)據(jù) this.props 之前的props數(shù)據(jù)
// nextState 最新的state數(shù)據(jù) this.state 之前的state數(shù)據(jù)
shouldComponentUpdate(nextProps, nextState) {
// 針對(duì)于要比較的字段進(jìn)行判斷
if (this.props.num.data === nextProps.num.data) {
return false
}
return true
}
render() {
console.log('child -- render')
return (
<div>
<h3>{this.props.num.data}</h3>
</div>
)
}
}
class App extends Component {
state = {
num: { data: 1 },
name: '張三'
}
render() {
console.log('app -- render')
return (
<div>
<h3>{this.state.num.data}</h3>
<Child num={this.state.num} />
{/* 這時(shí)子組件會(huì)更新 */}
{/* <button onClick={() => this.setState({ num: { data: Date.now() } })}>++num++</button> */}
<button onClick={() => this.setState({ num: { data: 1 } })}>++num++</button>
</div>
)
}
}
export default App
擴(kuò)展:使用lodash庫減小無效渲染
import React, { Component, PureComponent } from 'react'
import _ from 'lodash'
class Child extends Component {
// 此方法,用于組件重復(fù)渲染的優(yōu)化方法,它不是必須要用的
// 此方法必須要有一個(gè)boolean返回值
// 此方法只有在更新時(shí)才會(huì)觸發(fā)
// true 則繼續(xù)向下渲染 render
// false 表示當(dāng)前不會(huì)繼續(xù)渲染,從而減少無用渲染,提升性能
shouldComponentUpdate(nextProps, nextState) {
// 深層比對(duì),它比對(duì)的是對(duì)象中屬性的值,如果全局的值一樣則為true,否則為false
return !_.isEqual(this.props, nextProps)
}
render() {
console.log('child -- render')
return (
<div>
<h3>{this.props.num.data}</h3>
</div>
)
}
}
class App extends Component {
state = {
num: { data: 1 },
name: '張三'
}
render() {
console.log('app -- render')
return (
<div>
<h3>{this.state.num.data}</h3>
<Child num={this.state.num} />
{/* 這時(shí)子組件會(huì)更新 */}
{/* <button onClick={() => this.setState({ num: { data: Date.now() } })}>++num++</button> */}
<button onClick={() => this.setState({ num: { data: 1 } })}>++num++</button>
</div>
)
}
}
export default App
到此這篇關(guān)于React生命周期函數(shù)深入全面介紹的文章就介紹到這了,更多相關(guān)React生命周期函數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
React版本18.xx降低為17.xx的方法實(shí)現(xiàn)
由于現(xiàn)在react默認(rèn)創(chuàng)建是18.xx版本,但是我們現(xiàn)在大多使用的還是17.xx或者更低的版本,于是要對(duì)react版本進(jìn)行降級(jí),本文主要介紹了React版本18.xx降低為17.xx的方法實(shí)現(xiàn),感興趣的可以了解一下2023-11-11
React中Portals與錯(cuò)誤邊界處理實(shí)現(xiàn)
本文主要介紹了React中Portals與錯(cuò)誤邊界處理實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-07-07
react.js組件實(shí)現(xiàn)拖拽復(fù)制和可排序的示例代碼
這篇文章主要介紹了react.js組件實(shí)現(xiàn)拖拽復(fù)制和可排序的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-08-08
在Create React App中使用CSS Modules的方法示例
本文介紹了如何在 Create React App 腳手架中使用 CSS Modules 的兩種方式。有一定的參考價(jià)值,有需要的朋友可以參考一下,希望對(duì)你有所幫助。2019-01-01
ReactiveCocoa代碼實(shí)踐之-UI組件的RAC信號(hào)操作
這篇文章主要介紹了ReactiveCocoa代碼實(shí)踐之-UI組件的RAC信號(hào)操作 的相關(guān)資料,需要的朋友可以參考下2016-04-04

