React類組件更新的底層邏輯案例詳解
創(chuàng)建一個(gè)構(gòu)造函數(shù)(類)
- 類組件必須繼承自
React.Component
或React.PureComponent
。 - 在類組件中,需要定義 render 方法來(lái)返回需要渲染的視圖。
- 通常使用ES6中的class創(chuàng)建類。
class MyComponent extends React.Component { constructor(props) { super(props); // 調(diào)用父類構(gòu)造函數(shù) console.log(this.props); // 獲取傳遞的屬性 this.state = { count: 0 }; // 初始化狀態(tài) } //返回渲染的視圖 render() { return <div>{this.state.count}</div>; } }
類組件初始化
1. 初始化屬性 && 規(guī)則校驗(yàn)
首先會(huì)進(jìn)行規(guī)則校驗(yàn),校驗(yàn)完畢后,再處理屬性的其他操作。處理傳進(jìn)來(lái)的屬性有兩種處理方式:
方案一:
constructor(props) { super(props); //會(huì)把傳遞進(jìn)來(lái)的屬性掛載到this實(shí)例上 console.log(this.props); //獲取到傳遞的屬性 }
方案二:
不在constructor
中處理「或者constructor
都沒(méi)寫」,在constructor
處理完畢后,React內(nèi)部也會(huì)把傳遞的props
掛載到實(shí)例上。所以在其他的函數(shù)中,只要保證this
是實(shí)例,就可以基于this.props
獲取傳遞的屬性。同樣this.props
獲取的屬性對(duì)象也是被凍結(jié)的{只讀的} Object.isFrozen(this.props)->true
。
2. 初始化狀態(tài)
狀態(tài):后期修改狀態(tài),可以觸發(fā)視圖的更新。需要手動(dòng)初始化,如果我們沒(méi)有去做相關(guān)的處理,則默認(rèn)會(huì)往實(shí)例上掛載一個(gè)state,初始值是null => this.state=null
, 手動(dòng)處理則需要寫個(gè)state
對(duì)象:
state = { ... };
如何修改狀態(tài),控制視圖更新
this.state.xxx=xxx
上面的操作僅僅是修改了狀態(tài)值,但是無(wú)法讓視圖更新,想讓視圖更新,我們需要基于React.Component.prototype
提供的方法操作:
this.setState(partialState)
既可以修改狀態(tài),也可以讓視圖更新 「推薦」 ,其中partialState
部分狀態(tài)
this.setState({ xxx:xxx });
this.forceUpdate()
強(qiáng)制更新
3、觸發(fā) componentWillMount
componentWillMount
:組件第一次渲染之前觸發(fā)。
鉤子函數(shù):在程序運(yùn)行到某個(gè)階段,我們可以基于提供一個(gè)處理函數(shù),讓開(kāi)發(fā)者在這個(gè)階段做一些自定義的事情
??注意:此周期函數(shù),目前是不安全
的「雖然可以用,但是未來(lái)可能要被移除了,所以不建議使用」,控制會(huì)拋出黃色警告「為了不拋出警告,我們可以暫時(shí)用 UNSAFE_componentWillMount
」
??注意:如果開(kāi)啟了React.StrictMode
「React的嚴(yán)格模式」,則我們使用 UNSAFE_componentWillMount
這樣的周期函數(shù),控制臺(tái)會(huì)直接拋出紅色警告錯(cuò)誤??!
React.StrictMode VS “use strict”
- “use strict”:JS的嚴(yán)格模式
- React.StrictMode:React的嚴(yán)格模式,它會(huì)去檢查React中一些不規(guī)范的語(yǔ)法、或者是一些不建議使用的API等??!
4、觸發(fā) render 進(jìn)行渲染
5、觸發(fā) componentDidMount
componentDidMount
:第一次渲染完畢,此時(shí)已經(jīng)把virtualDOM變?yōu)檎鎸?shí)DOM了,可以獲取真實(shí)DOM
組件更新的邏輯
第一種:組件內(nèi)部的狀態(tài)被修改,組件會(huì)更新
1、觸發(fā) shouldComponentUpdate
shouldComponentUpdate
:是否允許更新,返回值決定視圖是否需要更新
shouldComponentUpdate(nextProps, nextState) { // nextState:存儲(chǔ)要修改的最新?tīng)顟B(tài) // this.state:存儲(chǔ)的還是修改前的狀態(tài)「此時(shí)狀態(tài)還沒(méi)有改變」 console.log(this.state, nextState); // 此周期函數(shù)需要返回true/false // 返回true:允許更新,會(huì)繼續(xù)執(zhí)行下一個(gè)操作 // 返回false:不允許更新,接下來(lái)啥都不處理 return true; }
2、觸發(fā) componentWillUpdate
componentWillUpdate
:更新之前,此周期函數(shù)也是不安全
的, 在這個(gè)階段,狀態(tài)/屬性還沒(méi)有被修改。
3、修改狀態(tài)值/屬性值
讓this.state.xxx
改為最新的值
4、觸發(fā) render
進(jìn)行組件渲染,處于經(jīng)歷下面過(guò)程:
- 按照最新的狀態(tài)/屬性,把返回的JSX編譯為virtualDOM
- 和上一次渲染出來(lái)的virtualDOM進(jìn)行對(duì)比「
DOM-DIFF
」 - 把差異的部分進(jìn)行渲染「渲染為真實(shí)的DOM」
5、 觸發(fā) componentDidUpdate
componentDidUpdate
:組件更新完畢。
??注意:如果我們是基于 this.forceUpdate()
強(qiáng)制更新視圖,會(huì)跳過(guò) shouldComponentUpdate
周期函數(shù)的校驗(yàn),直接從 componentWillUpdate
開(kāi)始進(jìn)行更新,也就是視圖一定會(huì)觸發(fā)更新。
第二種:父組件更新,觸發(fā)的子組件更新
1、觸發(fā) componentWillReceiveProps
componentWillReceiveProps
:接收最新屬性之前,該周期函數(shù)是不安全
的。
UNSAFE_componentWillReceiveProps(nextProps) { // this.props:存儲(chǔ)之前的屬性 // nextProps:傳遞進(jìn)來(lái)的最新屬性值 console.log('componentWillReceiveProps:', this.props, nextProps); }
2、觸發(fā) shouldComponentUpdate 周期函數(shù)
接下來(lái)的邏輯跟第一種一樣
組件卸載的邏輯
觸發(fā) componentWillUnmount
componentWillUnmount
:組件銷毀之前
銷毀
擴(kuò)展:父子組件嵌套更新邏輯
父子組件嵌套,處理機(jī)制上遵循深度優(yōu)先原則:父組件在操作中,遇到子組件,一定是把子組件處理完,父組件才能繼續(xù)處理
父組件第一次渲染
父 willMount -> 父 render「子 willMount -> 子 render -> 子didMount」 -> 父didMount
父組件更新
父 shouldUpdate -> 父willUpdate -> 父 render 「子willReceiveProps -> 子 shouldUpdate -> 子willUpdate -> 子 render -> 子 didUpdate」-> 父 didUpdate
父組件銷毀
父 willUnmount -> 處理中「子willUnmount -> 子銷毀」-> 父銷毀
源碼
import React from "react"; import PropTypes from 'prop-types'; class Vote extends React.Component { /* 屬性規(guī)則校驗(yàn) */ static defaultProps = { num: 0 }; static propTypes = { title: PropTypes.string.isRequired, num: PropTypes.number }; /* 初始化狀態(tài) */ state = { supNum: 20, oppNum: 10 }; render() { console.log('render:渲染'); let { title } = this.props, { supNum, oppNum } = this.state; return <div className="vote-box"> <div className="header"> <h2 className="title">{title}</h2> <span>{supNum + oppNum}人</span> </div> <div className="main"> <p>支持人數(shù):{supNum}人</p> <p>反對(duì)人數(shù):{oppNum}人</p> </div> <div className="footer"> <button onClick={() => { this.setState({ supNum: supNum + 1 }); }}>支持</button> <button onClick={() => { this.state.oppNum++; this.forceUpdate(); }}>反對(duì)</button> </div> </div>; } UNSAFE_componentWillMount() { console.log('componentWillMount:第一次渲染之前'); } componentDidMount() { console.log('componentDidMount:第一次渲染完畢'); } shouldComponentUpdate(nextProps, nextState) { console.log('shouldComponentUpdate:', this.state, nextState); return true; } UNSAFE_componentWillUpdate(nextProps, nextState) { console.log('componentWillUpdate:', this.state, nextState); } componentDidUpdate() { console.log('componentDidUpdate:組件更新完畢'); } UNSAFE_componentWillReceiveProps(nextProps) { console.log('componentWillReceiveProps:', this.props, nextProps); } componentWillUnmount() { console.log('componentWillUnmount:組件銷毀之前'); } } export default Vote;
初始渲染:
點(diǎn)擊支持:更新渲染:
點(diǎn)擊反對(duì),更新渲染,因?yàn)槭褂昧?code>forceUpdate(),所以直接跳過(guò)了shouldComponentUpdate
周期:
父組件更新,觸發(fā)的子組件更新,這次回觸發(fā)componentWillReceiveProps
組件更新渲染邏輯如下圖所示
簡(jiǎn)單總結(jié)一下:
組件初始化階段
constructor(props)
:用于初始化組件的屬性和狀態(tài)。UNSAFE_componentWillMount()
:在組件渲染前調(diào)用,但不推薦使用,可能在未來(lái)版本中被移除。render()
:渲染組件,返回 JSX 元素。componentDidMount()
:在組件渲染完成后調(diào)用,可以在此進(jìn)行異步操作或 DOM 操作。
組件更新階段
shouldComponentUpdate(nextProps, nextState)
:用于決定組件是否需要更新,返回 true 或 false。UNSAFE_componentWillUpdate(nextProps, nextState)
:在組件更新前調(diào)用,但不推薦使用,未來(lái)可能移除。- `render():再次渲染組件。
componentDidUpdate(prevProps, prevState)
:組件更新后調(diào)用,可以在此進(jìn)行后續(xù)操作。
組件卸載階段
componentWillUnmount()
:在組件銷毀之前調(diào)用,可以在此進(jìn)行清理操作,如取消訂閱、清除定時(shí)器等。
到此這篇關(guān)于React類組件更新的底層邏輯的文章就介紹到這了,更多相關(guān)React類組件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
react-redux及redux狀態(tài)管理工具使用詳解
Redux是為javascript應(yīng)用程序提供一個(gè)狀態(tài)管理工具集中的管理react中多個(gè)組件的狀態(tài)redux是專門作狀態(tài)管理的js庫(kù)(不是react插件庫(kù)可以用在其他js框架中例如vue,但是基本用在react中),這篇文章主要介紹了react-redux及redux狀態(tài)管理工具使用詳解,需要的朋友可以參考下2023-01-01React使用TypeScript的最佳實(shí)踐和技巧
在React項(xiàng)目中使用TypeScript可以顯著提高代碼的可維護(hù)性和可讀性,并提供強(qiáng)大的類型檢查功能,減少運(yùn)行時(shí)錯(cuò)誤,以下是一些優(yōu)雅地將TypeScript集成到React項(xiàng)目中的最佳實(shí)踐和技巧,需要的朋友可以參考下2024-06-06教你react中如何理解usestate、useEffect副作用、useRef標(biāo)識(shí)和useContext
這篇文章主要介紹了react中如何理解usestate、useEffect副作用、useRef標(biāo)識(shí)和useContext,其實(shí)與vue中的ref和reactive一樣,通過(guò)useState獲取到的數(shù)據(jù)可以實(shí)現(xiàn)組件視圖實(shí)時(shí)交互,而普通定義的數(shù)據(jù)僅僅在業(yè)務(wù)中使用,需要的朋友可以參考下2022-11-11React?hooks中useState踩坑之異步的問(wèn)題
這篇文章主要介紹了React?hooks中useState踩坑之異步的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03高性能React開(kāi)發(fā)React Server Components詳解
ReactServerComponents通過(guò)服務(wù)器端渲染、自動(dòng)代碼分割等技術(shù),實(shí)現(xiàn)了高性能的React開(kāi)發(fā),它解決了客戶端數(shù)據(jù)請(qǐng)求鏈?zhǔn)窖舆t、敏感數(shù)據(jù)暴露風(fēng)險(xiǎn)等問(wèn)題,提供了更好的用戶體驗(yàn)和安全性,本文介紹高性能React開(kāi)發(fā)React Server Components詳解,感興趣的朋友一起看看吧2025-03-03react結(jié)合typescript?封裝組件實(shí)例詳解
這篇文章主要為大家介紹了react結(jié)合typescript?封裝組件實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04React18使用Echarts和MUI實(shí)現(xiàn)一個(gè)交互性的溫度計(jì)
這篇文章我們將結(jié)合使用React 18、Echarts和MUI(Material-UI)庫(kù),展示如何實(shí)現(xiàn)一個(gè)交互性的溫度計(jì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-01-01