網站首頁 編程語言 正文
1.?注意
函數組件無生命周期,生命周期只有類組件才擁有。
2. 圖解
完整的生命周期主要為三個部分,分別為掛載時、更新時和卸載時,如下圖所示:
3. 生命周期函數
3.1 constructor構造函數
描述:
React 組件的構造函數在掛載之前被調用。在實現 React.Component 構造函數時,需要先在添加其它內容前,調用 super(props),用來將父組件傳來的 props 綁定到繼承類中。
構造函數它只執行1次,可以進行數據初始化操作,因為它是所有的生命周期中第1個被執行的方法,但是不太建議在此方法中進行網絡請求。
父組件的構造方法先執行,子組件的構造方法后執行。
語法:
constructor(props) { // 如果你在定義組件中有定義構造函數,則一定要調用super方法來調用父類的構造函數 super(props) // todo … }
3.2 static getDerivedStateFromProps(nextProps, prevState)方法
描述:
此方法在構造函數方法之后,Render 方法之前被調用,并且在初始掛載及后續更新時都會被調用。它應返回一個對象來更新 state,如果返回 null 則不更新任何內容。
此方法適用于罕見的用例,即當前組件的 state 的值在任何時候都取決于 props 傳入。
語法:
state = { num: 0 }; render() { return <div>當前的num是{this.state.num}</div>; } // 從props中獲取數據,綁定到當前的這個組件中的state // nextProps 父組件傳遞過來的整個props對象,即當前最新的props數據 // prevState 當前組件中的狀態對象state,即當前最新的state數據,但暫時不包含返回值中要對state修改的值 static getDerivedStateFromProps(nextProps, prevState) { // 不需要更新當前state return null }
注意:
- 此方法會執行 n 次
- 此方法它是一個靜態方法,靜態方法中不能使用 this
- 使用此方法一定要先定義好 state,否則報錯
- 此方法必須要有返回值,
{}|null
,如果返回為對象,則會對 state 中數據進行操作,返回的對象屬性如果在 state 中沒有則添加,有則修改;如果返回為 null,則不會對 state 進行任何操作
getDerivedStateFromProps 在父子組件中執行的先后順序,及 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: 當前最新的state數據,暫時不包含你返回值中要對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 } // 父組件先執行后子組件執行此方法 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
注意:由于這個方法會執行 n 次,所以不建議在這個方法中發送網絡請求,容易造成死循環。如果想要在這個方法中發送網絡請求,則一定要確保不要觸發這個方法再次執行(即父組件不發送新的 props 或修改 props ,不修改 state ,不強制更新視圖)
小案例:
描述:
子組件將 state 中的數據修改為 nextProps 中的值,并且點擊增加按鈕能夠觸發后續對值的修改。
實現:
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中的屬性數據,追加到state中,后續能修改,則這樣的操作,你要確保只執行1次 // 這種方式只能接收到父組件第一次值過來的值(10),點擊按鈕子組件age并不會增加 // 這是因為每次點擊增加按鈕都會觸發當前函數,將state中的age修改為nextProps // return nextProps // 這種方式不會觸發點擊按鈕增加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 掛載時和更新時的生命周期函數執行順序
掛載時生命周期函數介紹:
- constructor(props)
React組件的構造函數在掛載之前被調用。在實現React.Component構造函數時,需要先在添加其它內容前,調用super(props),用來將父組件傳來的props綁定到繼承類中。只調用一次。
- static getDerivedStateFromProps(nextProps, prevState)
此方法是react16.3之后新增,會在調用 render 方法之前調用,并且在初始掛載及后續更新時都會被調用。它應返回一個對象來更新 state,如果返回 null 則不更新任何內容。
此方法適用于罕見的用例,即當前組件的 state 的值在任何時候都取決于 props傳入。
- render()
render()方法是必需的,它主要負責組件的渲染,會被重復調用若干次
- componentDidMount
它會在組件掛載后(插入 DOM 樹中)立即調用。依賴于 DOM 節點的初始化應該放在這里。如需通過網絡請求獲取數據,此處是實例化請求的好地方。
- shouldComponentUpdate(nextProps, nextState)
此函數將放在下文單獨講解。
- getSnapshotBeforeUpdate(prevProps, prevState)
在最近一次渲染輸出(提交到 DOM 節點)之前調用。它使得組件能在發生更改之前從 DOM 中捕獲一些信息,此生命周期的任何返回值將作為參數傳遞給 componentDidUpdate()
- componentDidUpdate(prevProps, prevState, snapshot)
會在數據更新后被立即調用。首次渲染不會執行此方法。
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 } // 它只執行1次 // 虛擬dom掛載到真實的頁面點中完成,在此進行dom操作 // 在此可以進行網絡請求 componentDidMount() { console.log('child -- componentDidMount') } // ------------- 更新時 // prevProps 修改之前的props數據 // prevState 修改之前的state數據 // 此方法要有一個返回值,且如果有此方法,則必須要有componentDidUpdate // 此方法的返回值,會在componentDidUpdate參數3中接受 getSnapshotBeforeUpdate(prevProps, prevState) { console.log('child --- getSnapshotBeforeUpdate') return 100 } // 數據更新完畢后執行 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 } // 數據更新完畢后執行 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
掛載時:
更新時:
3.4 componentWillUnmount函數的使用
描述:
componentWillUnmount() 會在組件卸載及銷毀之前直接調用。在此方法中執行必要的清理操作。
使用:
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 } // 銷毀組件時執行 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 } // 數據更新完畢后執行 componentDidUpdate(prevProps, prevState, snapshot) { console.log('App --- componentDidUpdate', snapshot) } render() { let { age } = this.state return ( <div> <h3>App組件 -- {age}</h3> {/* age大于1時銷毀子組件 */} {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優化渲染方案
描述:
React 的更新機制導致,即使子組件未發生更新,只要父組件中的 state 改變,當前父組件及其所有子組件都會重新渲染,這樣做雖然很高效,但會造成不少性能損耗,那么該如何避免呢?
當 props 或 state 發生變化時,shouldComponentUpdate() 會在渲染執行之前被調用。返回值默認為 true 則組件繼續渲染,為 false 則當前組件不會渲染。首次渲染或使用 forceUpdate() 時不會調用該方法。此方法僅作為性能優化的方式而存在。你也可以考慮使用內置的 PureComponent 組件,而不是手動編寫 shouldComponentUpdate()。
PureComponent 會對 props 和 state 進行淺層比較,并減少了跳過必要更新的可能性。 PureComponent 它可以對于組件無效渲染起到一定的優化,但是它只能針對于props中值為基本類型。
所以我們還可以使用生命周期中提供的優化方案,使用 shouldComponentUpdate 減少無效渲染次數。
語法:
shouldComponentUpdate(nextProps, nextState) { // 判斷是否需要被渲染,如果需要則返回true,否則返回false if (nextProps.b === this.props.b) { return false; } else { return true; } } // 簡化方法:只需要將類組件的繼承關系改成繼承`PureComponent`即可,這樣一來,框架會自動判斷值是否有變化進一步決定組件是否需要被渲染。 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 它可以對于組件無效渲染起到一定的優化,但是它只能針對于props中值為基本類型 // 可以使用生命周期中提供的優化方案,提升無效渲染次數 // class Child extends PureComponent { class Child extends Component { // 此方法,用于組件重復渲染的優化方法,它不是必須要用的 // 此方法必須要有一個boolean返回值 // 此方法只有在更新時才會觸發 // true 則繼續向下渲染 render // false 表示當前不會繼續渲染,從而減少無用渲染,提升性能 // nextProps 最新的props數據 this.props 之前的props數據 // nextState 最新的state數據 this.state 之前的state數據 shouldComponentUpdate(nextProps, nextState) { // 針對于要比較的字段進行判斷 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} /> {/* 這時子組件會更新 */} {/* <button onClick={() => this.setState({ num: { data: Date.now() } })}>++num++</button> */} <button onClick={() => this.setState({ num: { data: 1 } })}>++num++</button> </div> ) } } export default App
擴展:使用lodash庫減小無效渲染
import React, { Component, PureComponent } from 'react' import _ from 'lodash' class Child extends Component { // 此方法,用于組件重復渲染的優化方法,它不是必須要用的 // 此方法必須要有一個boolean返回值 // 此方法只有在更新時才會觸發 // true 則繼續向下渲染 render // false 表示當前不會繼續渲染,從而減少無用渲染,提升性能 shouldComponentUpdate(nextProps, nextState) { // 深層比對,它比對的是對象中屬性的值,如果全局的值一樣則為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} /> {/* 這時子組件會更新 */} {/* <button onClick={() => this.setState({ num: { data: Date.now() } })}>++num++</button> */} <button onClick={() => this.setState({ num: { data: 1 } })}>++num++</button> </div> ) } } export default App
原文鏈接:https://blog.csdn.net/weixin_45605541/article/details/127022886
相關推薦
- 2022-03-27 帶你從內存的角度看Python中的變量_python
- 2022-05-26 Python?pass語句作用和Python?assert斷言函數的用法_python
- 2022-05-18 Python繪制散點圖的教程詳解_python
- 2022-05-09 React中的axios模塊及使用方法_React
- 2022-09-08 C++實現Dijkstra算法的示例代碼_C 語言
- 2022-09-30 Go語言編譯原理之變量捕獲_Golang
- 2022-03-23 如何解決Mac中的Docker宿主機與容器無法通信(MacOS下解決宿主機和docker容器網絡互通
- 2023-03-28 通知監控NotificationListenerService?onNotificationPost
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支