React 組件生命周期

来源:https://www.cnblogs.com/hubert-style/archive/2023/12/08/17888425.html
-Advertisement-
Play Games

求上進的人,不要總想著靠誰,人都是自私的,自己才是最靠得住的人。 React 中生命周期劃時代幾個節點,React 16.2 之前處於老的生命周期,之後提出了新的生命周期。而函數式組件在 React 16.8 之前是沒有狀態和生命周期的,在 React 16.8 版本通過引入 Hooks 使得函數式 ...


求上進的人,不要總想著靠誰,人都是自私的,自己才是最靠得住的人。

React 中生命周期劃時代幾個節點,React 16.2 之前處於老的生命周期,之後提出了新的生命周期。而函數式組件在 React 16.8 之前是沒有狀態和生命周期的,在 React 16.8 版本通過引入 Hooks 使得函數式組件也能有狀態和生命周期了。

1. 初始化階段

1.1 componentWillMount:

組件即將掛載,初始化數據作用,即 render 之前最後一次修改狀態的機會。

// 組件即將掛載
componentWillMount() {
  // 初始化數據作用
  console.log("componentWillMount")
}

/* 在 16.2 之後版本使用會出現以下警告 ⚠️⚠️⚠️
  react-dom.development.js:86 Warning: componentWillMount has been renamed, and is not recommended for use. See https://reactjs.org/link/unsafe-component-lifecycles for details.

  * Move code with side effects to componentDidMount, and set initial state in the constructor.
  * Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.

  Please update the following components: App
  */

// 組件即將掛載 - 強制去掉警告,UNSAFE 提示開發者這是一個不安全的生命周期方法。
UNSAFE_componentWillMount() {
  // 初始化數據作用
  console.log("componentWillMount")
}

componentWillMount 在16.2 之後官方不推薦使用了,這是因為 16.2 的時候 React 發生了一個改變,推出了幾個新的生命周期,老的生命周期方法被替代掉了,不推薦使用。 那麼為什麼 React 要推出新的生命周期呢?

在 React 16.2 中通過對 diff 演算法的更新,更加優化它的性能。提出了一個 Fiber 技術(纖維、分片、切片,比線程更小的一種概念)。因為我們傳統的 React 它在創建、更新狀態之後會創建新的虛擬 Dom 樹,會對比老的虛擬 Dom 樹,這個過程是同步的,如果數據量比較小還好。如果這個數據量非常多的情況下即組件非常多的情況下(例如:幾百個組件),這個時候更新操作,會導致我們瀏覽器假死、卡頓,這個時候點什麼都沒有反應,因為它忙著新老虛擬 Dom 的對比,就是它在對比兩個超級大的對象,裡面包含了很多小對象,這時瀏覽器無法處理其它事件,所以導致卡頓影響體驗。

所以這個東西就是一個邊緣化的問題,你的組件達到這樣一個程度,它真的會出現假死的情況。所以 React Fiber 技術就是來優化了虛擬 Dom 的 diff 演算法,它把創建 Dom 和組件渲染整個過程拆分成了無數個小的分片任務來執行。可以認為這個任務無比的碎片化,這個時候如果有優先順序較高的任務就先執行優先順序較高的任務。當優先順序較低的任務在執行時候突然來了優先順序較高的任務,這個時候會打斷正在執行的低優先順序任務,先執行優先順序高的任務。所謂的低優先順序任務就是 componentWillMount 中去找哪些節點將要去掛載到頁面中,而高優先順序任務就是 render 正在渲染,didMount 掛載完成。這個時候我們低優先順序的任務(找出那些需要更新的 Dom)這個過程是會被打斷的,而我們更新 Dom 這個過程是不能被打斷的,只能一鼓作氣做完的,而 willMount 很不幸它是處在這個要找出來那些 Dom 是需要被更新的。所以這個過程是可以被打斷的,所以可以認為 willMount 在忙著找出那些狀態需要更新。因為接下來在 render 中就要開始更新了,didMount 就更新完成了。這個時候 willMount 找是處於低優先順序的,而這個時候 render 正在更新,因為碎片化任務,他可能還不是同步的。即某個組件可能處在在找那個狀態需要更新,那個 Dom 需要更新,而那邊組件已經到了 render 渲染部分了,這個時候就吧低優先順序的任務給砍掉了。砍掉怎麼辦,會保存嗎?不會。只能下次再來一遍,再來找那個節點需要更新。所以這個生命周期就可能會觸發多次這樣一個問題(失去了唯一性),所以這是一個有隱患的生命周期方法,所以這裡不推薦使用。

1.2 render

組件正式掛載渲染,只能訪問 this.props 和 this.state,不允許修改狀態和 Dom 輸出。

1.3 componentDidMount

組件掛載完成,成功 render 並渲染完成真實 DOM 之後觸發,可以訪問、修改 Dom。

componentDidMount() {
  // 數據請求axios
  // 訂閱函數調用
  // setInterval
  // 基於創建的完的dom進行初始化時候,例如 BetterScroll 使用
  console.log("componentDidMount")
}

2. 運行中階段

2.1 componentWillUpdate

組件即將更新,不能修改屬性和狀態,會造成死迴圈。非安全被棄用,同 componentWillMount。

// 組件即將更新
componentWillUpdate() {
  console.log("componentWillUpdate")
}

/* 在 16.2 之後版本使用會出現以下警告 ⚠️⚠️⚠️
  react-dom.development.js:86 Warning: componentWillUpdate has been renamed, and is not recommended for use. See https://reactjs.org/link/unsafe-component-lifecycles for details.

* Move data fetching code or side effects to componentDidUpdate.
* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.

Please update the following components: App
  */

// 組件即將更新 - 強制去掉警告,UNSAFE 提示開發者這是一個不安全的生命周期方法。
 UNSAFE_componentWillUpdate() {
  console.log("componentWillUpdate")
}

2.2 render

組件正式掛載渲染,只能訪問 this.props 和 this.state,不允許修改狀態和 Dom 輸出。

2.3 componentDidUpdate

組件更新完成,成功 render 並渲染完成真實 DOM 之後觸發,可以訪問、修改 Dom。

// 組件更新完成 - 接收兩個行參,老的屬性、老的狀態
componentDidUpdate(prevProps, prevState) {
  console.log(prevState)
  console.log("componentDidUpdate")
}

2.4 shouldComponentUpdate

scu 控制組件是否應該更新,即是否執行 render 函數。

// 組件是否應該更新?- 接受兩個行參,新的屬性、新的狀態
shouldComponentUpdate(nextProps, nextState) {
  if (JSON.stringify(this.state) !== JSON.stringify(nextState)) {
    return true
  } else {
    return false
  }
}

2.5 componentWillReceiveProps

父組件修改屬性觸發,非安全被棄用,同 componentWillMount。處在 diff 中第一個階段,找到哪些需要更新的 Dom。例如:如果父組件連續多次修改屬性傳遞將觸發多次 ajax 請求等。

// 父組件修改屬性觸發,應用在子組件中才有意義
componentWillReceiveProps(nextProps) {
  // 最先獲得父組件傳來的屬性,可以利用屬性進行ajax或者邏輯處理
  // 把屬性轉換為孩子的自己的狀態等
}

3. 銷毀階段

3.1 componentWillUnmount

在刪除組件之前進行清理操作,比如計時器和事件監聽器。

4. 新生命周期

4.1 getDerivedStateFromProps

getDerivedStateFromProps 第一次的初始化組件以及後續的更新過程中(包括自身狀態更新以及父傳子),返回一個對象作為新的 state,返回 null 則說明不需要在這裡更新 state。

在初始化中代替 componentWillMount 。在父傳子中能代替 componentWillReceiveProps。

這裡不能做非同步操作,因為這裡 return 是立即返回的。

static getDerivedStateFromProps(nextProps, nextState) {
  console.log("getDerivedStateFromProps")
  return {

  }
}

4.2 getSnapshotBeforeUpdate

getSnapshotBeforeUpdate 取代了 componentDidUpdate,觸發時間為 update 發生的時候,在 render之後 Dom 渲染之前返回一個值,作為 componentDidUpdate 的第三個參數。

import React, { Component } from 'react'

export default class App extends Component {
  state = {

  }

  // getDerivedStateFromProps 第一次的初始化組件以及後續的更新過程中(包括自身狀態更新以及父傳子),返回一個對象作為新的 state,返回 null 則說明不需要在這裡更新 state
  // 這裡不能做非同步操作,因為這裡 return 是立即返回的
  static getDerivedStateFromProps(nextProps, nextState) {
    console.log("getDerivedStateFromProps")
    return {

    }
  }

  getSnapshotBeforeUpdate() {
    return 100
  }

  componentDidUpdate(prevProps, prevState, value) {
    console.log(value)
  } 

  render() {
    return (
      <div>
        <button onClick={()=>{
          this.setState({

          })
        }}>修改</button>
      </div>
    )
  }
}

5. React 中性能優化

5.1 shouldComponentUpdate

React 手動優化,控制組件自身或者子組件是否需要更新,尤其在子組件非常多的情況下,需要進行優化。

5.2 PureComponent

React 自動優化,PureComponent 會幫你比較新 props 跟舊的 props,新的 state 和老的 state(值相等,或者對象含有相同的屬性、且屬性值相等),決定 shouldComponentUpdate 返回 true 或者 false,從而決定要不要呼叫 render function。

註意:如果你的 state 或 props『永遠都會變』,那 PureComponent 並不會比較快,因為 shallowEqual 也需要花時間,比如倒計時功能,這就不適合使用 Pure Component 了。

5.3 緩存技術

React.Component 是使用 ES6 classes 方式定義 React 組件的基類:

class Greeting extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

PureComponent 和 memo 僅作為性能優化的方式而存在。但請不要依賴它來“阻止”渲染,因為這會產生 bug。PureComponnet 和 memo 都是通過對 props 值的淺比較來決定該組件是否需要更新的。

2.1 PureComponent (類組件)

React.PureComponent 與 React.Component 很相似。兩者的區別在於 React.Component 並未實現 shouldComponentUpdate(),而 React.PureComponent 中以淺層對比 props 和 state 的方式來實現了該函數。
如果賦予 React 組件相同的 props 和 state,render() 函數會渲染相同的內容,那麼在某些情況下使用 React.PureComponent 可提高性能。

2.2 memo(函數式組件)

函數組件緩存 memo,為啥起 memo 這個名字?在電腦領城,記記化是一種主要用來提高電腦程式速度的優化技術方案。它將開銷較大的函數調用的返回結果存儲起來,當同樣的輸入再次發生時,則這回緩存好的數據,以此提升運算效率。

React.memo 為高階組件。它與 React.PureComponent 非常相似,但只適用於函數組件,而不適用 class 組件。

const MyComponent = function MyComponent(props) {
  /* 使用 props 渲染 */
};
export default React.memo(MyComponent)

如果你的函數組件在給定相同 props 的情況下渲染相同的結果,那麼你可以通過將其包裝在 React.memo 中調用,以此通過記憶組件渲染結果的方式來提高組件的性能表現。這意味著在這種情況下,React 將跳過渲染組件的操作並直接復用最近一次渲染的結果,即組件僅在它的 props 發生改變的時候進行重新渲染。通常來說,在組件樹中 React 組件,只要有變化就會走一遍渲染流程。但是 React.memo(),我們可以僅僅讓某些組件進行渲染。

React.memo 僅檢查 props 變更。如果函數組件被 React.memo 包裹,且其實現中擁有 useState 或 useContext 的 Hook,當 context 發生變化時,它仍會重新渲染。

預設情況下其只會對複雜對象做淺層對比,如果你想要控制對比過程,那麼請將自定義的比較函數通過第二個參數傳入來實現。

function MyComponent(props) {
  /* 使用 props 渲染 */
}
function areEqual(prevProps, nextProps) {
  
}
export default React.memo(MyComponent, areEqual);

示例:

// 子組件代碼:
import React, { memo } from 'react';
const Child = ()=>{
	console.log("2. 子組件渲染了")
	return (<div>子組件</div>)
}
export default Child

// 父組件代碼:
import React, { memo } from 'react';
import Child from './Child.jsx'
const Father = ()=>{
	const [name,setName]=React.useState('');
	console.log("1. 父組件渲染了")
	return (<div>
		/* 在input框中輸入內容,會走setName導致App組件重新渲染,但是子組件Child也會進行渲染。 */
		父組件:<input type="text" value={name} onChange={ev=>setName(ev.target.value)} />
		<Child />
	</div>)
}
// 子組件代碼:
import React, { memo } from 'react';
const Child = ()=>{
	console.log("2. 子組件渲染了")
	return (<div>子組件</div>)
}
export default memo(Child)
// 父組件代碼:
import React, { memo } from 'react';
import Child from './Child.jsx'
const Father = ()=>{
	const [name,setName]=React.useState('');
	console.log("1. 父組件渲染了")
	return (<div>
		/* 解決:子組件使用memo包起來 */
		父組件:<input type="text" value={name} onChange={ev=>setName(ev.target.value)} />
		<Child />
	</div>)
}

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 本文要說的這種開發模式,這種模式並不是只有blazor支持,js中有一樣的方案next.js nuxt.js;blazor還有很多其它內容,本文近關註漸進式開發模式。 是的,前後端是主流,不過以下情況也許前後端分離並不是最好的選擇: 小公司,人員不多,利潤不高,創業階段能省則省 個人開發者,接 ...
  • 使用Aspirate可以將Aspire程式部署到Kubernetes 集群 工具安裝 dotnet tool install -g aspirate --prerelease 註意:Aspirate 正在開發中,該軟體包將作為預覽版進行版本控制,--prelease 選項將獲得最新的預覽版。 容器註 ...
  • 本篇將分享Prometheus+Grafana的監控平臺搭建,並監控之前文章所搭建的主機&服務,分享日常使用的一些使用經驗本篇將配置常用服務的監控與面板配置:包括 MySQL,MongoDB,CLickHouse,Redis,RabbitMQ,Linux,Windows,Nginx,站點訪問監控,已... ...
  • 當使用Autofac處理一個介面有多個實現的情況時,通常會使用鍵(key)進行區分或者通過IIndex索引註入,也可以通過IEnumerable集合獲取所有實例,以下是一個具體的例子,演示如何在Autofac中註冊多個實現,並通過構造函數註入獲取指定實現。 首先,確保你已經安裝了Autofac Nu ...
  • tmux教程 功能 分屏:可以在一個開發框里分屏 允許terminal在連接斷開之後可以繼續運行,讓進程不會因為斷開連接而中斷 結構 // 一個tmux可以包含多個session,一個session可以包含多個window,一個window可以包含多個pane。 tmux: session 0: w ...
  • 本文分享自華為雲社區《GaussDB資料庫SQL系列-層次遞歸查詢》,作者: Gauss松鼠會小助手2。 一、前言 層次遞歸查詢是一種常見的SQL查詢方式,特別是在一些層次化的數據存儲結構中經常用到。本文主要以GaussDB資料庫為實驗平臺,為大家講解其使用方法。 二、GuassDB資料庫層次遞歸查 ...
  • 在我們應用中的使用場景來看,簡單來說通常會看中了clickhouse在處理大批量數據的寫入和讀取分析方面的性能,MySQL會主要負責一些基於模型進行指標二次加工的高頻查詢及複雜join的查詢。 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 前言 大家好,今天聊一下在做uniapp多端適配項目,需要用到自定義導航時,如何解決狀態欄塌陷及導航欄安全區域多端適配問題,下文只針對H5、APP、微信小程式三端進行適配,通過封裝一個通用高階組件包裹自定義導航欄內容,主要是通過設置pad ...
一周排行
    -Advertisement-
    Play Games
  • 前言 微服務架構已經成為搭建高效、可擴展系統的關鍵技術之一,然而,現有許多微服務框架往往過於複雜,使得我們普通開發者難以快速上手並體驗到微服務帶了的便利。為瞭解決這一問題,於是作者精心打造了一款最接地氣的 .NET 微服務框架,幫助我們輕鬆構建和管理微服務應用。 本框架不僅支持 Consul 服務註 ...
  • 先看一下效果吧: 如果不會寫動畫或者懶得寫動畫,就直接交給Blend來做吧; 其實Blend操作起來很簡單,有點類似於在操作PS,我們只需要設置關鍵幀,滑鼠點來點去就可以了,Blend會自動幫我們生成我們想要的動畫效果. 第一步:要創建一個空的WPF項目 第二步:右鍵我們的項目,在最下方有一個,在B ...
  • Prism:框架介紹與安裝 什麼是Prism? Prism是一個用於在 WPF、Xamarin Form、Uno 平臺和 WinUI 中構建鬆散耦合、可維護和可測試的 XAML 應用程式框架 Github https://github.com/PrismLibrary/Prism NuGet htt ...
  • 在WPF中,屏幕上的所有內容,都是通過畫筆(Brush)畫上去的。如按鈕的背景色,邊框,文本框的前景和形狀填充。藉助畫筆,可以繪製頁面上的所有UI對象。不同畫筆具有不同類型的輸出( 如:某些畫筆使用純色繪製區域,其他畫筆使用漸變、圖案、圖像或繪圖)。 ...
  • 前言 嗨,大家好!推薦一個基於 .NET 8 的高併發微服務電商系統,涵蓋了商品、訂單、會員、服務、財務等50多種實用功能。 項目不僅使用了 .NET 8 的最新特性,還集成了AutoFac、DotLiquid、HangFire、Nlog、Jwt、LayUIAdmin、SqlSugar、MySQL、 ...
  • 本文主要介紹攝像頭(相機)如何採集數據,用於類似攝像頭本地顯示軟體,以及流媒體數據傳輸場景如傳屏、視訊會議等。 攝像頭採集有多種方案,如AForge.NET、WPFMediaKit、OpenCvSharp、EmguCv、DirectShow.NET、MediaCaptre(UWP),網上一些文章以及 ...
  • 前言 Seal-Report 是一款.NET 開源報表工具,擁有 1.4K Star。它提供了一個完整的框架,使用 C# 編寫,最新的版本採用的是 .NET 8.0 。 它能夠高效地從各種資料庫或 NoSQL 數據源生成日常報表,並支持執行複雜的報表任務。 其簡單易用的安裝過程和直觀的設計界面,我們 ...
  • 背景需求: 系統需要對接到XXX官方的API,但因此官方對接以及管理都十分嚴格。而本人部門的系統中包含諸多子系統,系統間為了穩定,程式間多數固定Token+特殊驗證進行調用,且後期還要提供給其他兄弟部門系統共同調用。 原則上:每套系統都必須單獨接入到官方,但官方的接入複雜,還要官方指定機構認證的證書 ...
  • 本文介紹下電腦設備關機的情況下如何通過網路喚醒設備,之前電源S狀態 電腦Power電源狀態- 唐宋元明清2188 - 博客園 (cnblogs.com) 有介紹過遠程喚醒設備,後面這倆天瞭解多了點所以單獨加個隨筆 設備關機的情況下,使用網路喚醒的前提條件: 1. 被喚醒設備需要支持這WakeOnL ...
  • 前言 大家好,推薦一個.NET 8.0 為核心,結合前端 Vue 框架,實現了前後端完全分離的設計理念。它不僅提供了強大的基礎功能支持,如許可權管理、代碼生成器等,還通過採用主流技術和最佳實踐,顯著降低了開發難度,加快了項目交付速度。 如果你需要一個高效的開發解決方案,本框架能幫助大家輕鬆應對挑戰,實 ...