React生命周期函數(shù)深入全面介紹
1. 注意
函數(shù)組件無(wú)生命周期,生命周期只有類組件才擁有。
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),用來(lái)將父組件傳來(lái)的 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í)行。
語(yǔ)法:
constructor(props) { // 如果你在定義組件中有定義構(gòu)造函數(shù),則一定要調(diào)用super方法來(lái)調(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ì)象來(lái)更新 state,如果返回 null 則不更新任何內(nèi)容。
此方法適用于罕見(jiàn)的用例,即當(dāng)前組件的 state 的值在任何時(shí)候都取決于 props 傳入。
語(yǔ)法:
state = { num: 0 }; render() { return <div>當(dāng)前的num是{this.state.num}</div>; } // 從props中獲取數(shù)據(jù),綁定到當(dāng)前的這個(gè)組件中的state // nextProps 父組件傳遞過(guò)來(lái)的整個(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 中沒(méi)有則添加,有則修改;如果返回為 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次 // 這種方式只能接收到父組件第一次值過(guò)來(lái)的值(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),用來(lái)將父組件傳來(lái)的props綁定到繼承類中。只調(diào)用一次。
- static getDerivedStateFromProps(nextProps, prevState)
此方法是react16.3之后新增,會(huì)在調(diào)用 render 方法之前調(diào)用,并且在初始掛載及后續(xù)更新時(shí)都會(huì)被調(diào)用。它應(yīng)返回一個(gè)對(duì)象來(lái)更新 state,如果返回 null 則不更新任何內(nèi)容。
此方法適用于罕見(jiàn)的用例,即當(dāng)前組件的 state 的值在任何時(shí)候都取決于 props傳入。
- render()
render()方法是必需的,它主要負(fù)責(zé)組件的渲染,會(huì)被重復(fù)調(diào)用若干次
- componentDidMount
它會(huì)在組件掛載后(插入 DOM 樹(shù)中)立即調(diào)用。依賴于 DOM 節(jié)點(diǎn)的初始化應(yīng)該放在這里。如需通過(guò)網(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í)的頁(yè)面點(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)行淺層比較,并減少了跳過(guò)必要更新的可能性。 PureComponent 它可以對(duì)于組件無(wú)效渲染起到一定的優(yōu)化,但是它只能針對(duì)于props中值為基本類型。
所以我們還可以使用生命周期中提供的優(yōu)化方案,使用 shouldComponentUpdate 減少無(wú)效渲染次數(shù)。
語(yǔ)法:
shouldComponentUpdate(nextProps, nextState) { // 判斷是否需要被渲染,如果需要?jiǎng)t返回true,否則返回false if (nextProps.b === this.props.b) { return false; } else { return true; } } // 簡(jiǎn)化方法:只需要將類組件的繼承關(guān)系改成繼承`PureComponent`即可,這樣一來(lái),框架會(huì)自動(dòng)判斷值是否有變化進(jìn)一步?jīng)Q定組件是否需要被渲染。 import React, { PureComponent } from "react"; class Cmp extends PureComponent { render() { console.log("Cmp被渲染了"); return <div>父親傳遞過(guò)來(lái)的值b為:{this.props.b}</div>; } } export default Cmp
使用:
import React, { Component, PureComponent } from 'react' // PureComponent 它可以對(duì)于組件無(wú)效渲染起到一定的優(yōu)化,但是它只能針對(duì)于props中值為基本類型 // 可以使用生命周期中提供的優(yōu)化方案,提升無(wú)效渲染次數(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ù)渲染,從而減少無(wú)用渲染,提升性能 // 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庫(kù)減小無(wú)效渲染
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ù)渲染,從而減少無(wú)用渲染,提升性能 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)文章
如何使用Redux Toolkit簡(jiǎn)化Redux
redux-toolkit是目前redux官方推薦的編寫redux邏輯的方法,針對(duì)redux的創(chuàng)建store繁瑣、樣板代碼太多、依賴外部庫(kù)等問(wèn)題進(jìn)行了優(yōu)化,官方總結(jié)了四個(gè)特點(diǎn)是簡(jiǎn)易的/有想法的/強(qiáng)勁的/高效的,總結(jié)來(lái)看,就是更加的方便簡(jiǎn)單了2022-12-12React?中如何將CSS?visibility?屬性設(shè)置為?hidden
這篇文章主要介紹了React中如何將CSS?visibility屬性設(shè)置為?hidden,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-05-05關(guān)于react+antd樣式不生效問(wèn)題的解決方式
最近本人在使用Antd開(kāi)發(fā)時(shí)遇到些問(wèn)題,所以下面這篇文章主要給大家介紹了關(guān)于react+antd樣式不生效問(wèn)題的解決方式,文中通過(guò)圖文以及實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-07-07React Refs轉(zhuǎn)發(fā)實(shí)現(xiàn)流程詳解
Refs是一個(gè) 獲取 DOM節(jié)點(diǎn)或React元素實(shí)例的工具,在React中Refs 提供了一種方式,允許用戶訪問(wèn)DOM 節(jié)點(diǎn)或者在render方法中創(chuàng)建的React元素,這篇文章主要給大家介紹了關(guān)于React中refs的一些常見(jiàn)用法,需要的朋友可以參考下2022-12-12React?UI組件庫(kù)之快速實(shí)現(xiàn)antd的按需引入和自定義主題
react入門學(xué)習(xí)告一段路,下面這篇文章主要給大家介紹了關(guān)于React?UI組件庫(kù)之快速實(shí)現(xiàn)antd的按需引入和自定義主題的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-07-07react中關(guān)于函數(shù)調(diào)用()與bind this的原因及分析
這篇文章主要介紹了react中關(guān)于函數(shù)調(diào)用()與bind this的原因及分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02