溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

React中setState的更新機制是什么

發(fā)布時間:2022-01-10 13:37:15 來源:億速云 閱讀:294 作者:iii 欄目:web開發(fā)

這篇文章主要介紹“React中setState的更新機制是什么”,在日常操作中,相信很多人在React中setState的更新機制是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”React中setState的更新機制是什么”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

setState作為react中的重要部分,將對組件 state 的更改排入隊列,并通知 React 需要使用更新后的 state 重新渲染此組件及其子組件。

React中setState的更新機制是什么

stateReact中的重要概念。我們知道,React是通過狀態(tài)管理來實現(xiàn)對組件的管理。那么,React是如何控制組件的狀態(tài)的,又是如何利用狀態(tài)來管理組件的呢?【相關推薦:Redis視頻教程】

我們都知道,React通過this.state來訪問state,通過this.setState()方法更新state。當this.setState()被調用的時候,React會重新調用render方法來重新渲染UI。

setState已經(jīng)是我們非常熟悉的一個API,然而你真的了解它嗎?下面我們將一起來解密setState的更新機制。

setState異步更新

大家剛開始寫React的時候,通常會寫出 this.state.value = 1 這樣的代碼,這是完全錯誤的寫法。

注意:絕對不要直接修改 this.state,這不僅是一種低效的做法,而且很有可能會被之后的操作替換。

setState通過一個隊列機制實現(xiàn)state更新。當執(zhí)行setState時,會將需要更新的state合并后放入狀態(tài)對列,而不會立刻更新this.state,隊列機制可以高效地批量更新state。如果不通過setState而直接修改this.state的值,那么該state將不會被放入狀態(tài)隊列中,當下次調用setState 并對狀態(tài)隊列進行合并時,將會忽略之前直接被修改的 state,而造成無法預知的錯誤。

因此,應該使用 setState 方法來更新 state,同時 React 也正是利用狀態(tài)隊列機制實現(xiàn)了 setState的異步更新,避免頻繁地重復更新 state。相關代碼如下:

// 將新的state合并到狀態(tài)更新隊列中
var nextState = this._processPendingState(nextProps, nextContext);

// 根據(jù)更新隊列和 shouldComponentUpdate 的狀態(tài)來判斷是否需要更新組件
var shouldUpdate = this._pendingForceUpdte || !inst.shouldCompoonentUpdate || inst.shouldComponentUpdate(nextProps, nextState, nextContext0;

setState循環(huán)調用風險

當調用setState時,實際上會執(zhí)行 enqueueSetState 方法,并對 partialState 以及 _pendingStateQueue 更新隊列進行合并操作,最終操作 enqueueSetState 執(zhí)行 state 更新。

performUpdateIfNecessary 方法會獲取 _pendingElement、_pendingStateQueue、_pendingForceUpdate,并調用 receiveComponentupdateComponent 方法進行組件更新。

如果在 shouldComponetUpdatecomponentWillUpdate 方法中調用 setState, 此時 this._pendingStateQueue != null, 則 performUpateIfNecessary 方法就會調用 updateComponent 方法進行組件更新,但 updateComponent 方法又會調用 shouldComponentUpdatecomponentWillUpdate 方法,因此造成循環(huán)調用,使得瀏覽器內存占滿后崩潰。

React中setState的更新機制是什么

setState調用棧

既然 setState 最終是通過 enqueueUpate 執(zhí)行 state 更新,那么 enqueueUpdate 到底是如何更新 state 的呢?

首先,看看下面這個問題,你是否能夠正確回答呢?

import React, { Component } from 'react'

class Example extends Component {
  constructor() {
    super()
    this.state = {
      val: 0
    }
  }
  
  componentDidMount() {
    this.setState({val: this.state.val + 1})
    console.log(this.state.val) 
    
    this.setState({val: this.state.val + 1})
    console.log(this.state.val) 
    
    setTimeout(() => {
      this.setState({val: this.state.val + 1})
      console.log(this.state.val) 
      this.setState({val: this.state.val + 1})
      console.log(this.state.val) 
    },0)
  }
  
  render() {
    return null
  }
}

上述代碼中, 4 次 console.log 打印出來的 val 分別是:0、0、2、3

假如結果與你心中的答案不完全相同,那么你是否想知道 enqueueUpdate 到底做了什么? 下圖是一個簡化的 setState 調用棧,注意其中核心的狀態(tài)判斷。

React中setState的更新機制是什么

setState簡化調用棧

解密setState

到底是怎么導致 setState 的各種不同表現(xiàn)的呢?

我們先要了解事務跟 setState 的不同表現(xiàn)有什么關系。首先,我們把4次 setState 簡單歸類,前兩次屬于一類,因為他們在同一次調用棧中執(zhí)行,setTimeout 中的兩次 setState 屬于另一類,因為他們也是在同一次調用棧中執(zhí)行。我們分析一下這兩類 setState 的調用棧。

componentDidMount 中直接調用的兩次 setState,其調用棧更加復雜;而setTimeout 中調用的兩次 setState,其調用棧則簡單很多。下面我們重點看看第一類 setState 的調用棧,我們發(fā)現(xiàn)了 batchedUpdates 方法,原來早在 setState 調用前,已經(jīng)處于batchedUpdates執(zhí)行的事務中了。

batchedUpdates方法,又是誰調用的呢?我們再往前追溯一層,原來是 ReactMount.js 中的 _renderNewRootComponent方法。也就是說,整個將React組件渲染到DOM中的過程就處于一個大的事務中。

接下來的解釋就順理成章了,因為在componentDidMount中調用setState時,batchingStrategyisBatchingUpdates 已經(jīng)被設為true,所以兩次setState的結果并沒有立即生效,而是被放到了dirtyComponents中。這也解釋了兩次打印 this.state.val 都是 0 的原因,因為新的 state 還沒有被應用到組件中。

React中setState的更新機制是什么

componentDidMountsetState的調用棧

React中setState的更新機制是什么

setTimeoutsetState的調用棧

再反觀 setTimeout 中的兩次setState,因為沒有前置的 batchedUpdate 調用,所以 batchingStrategyisBatchingUpates 標志位是false,也就導致了新的 state 馬上生效,沒有走到 dirtyComponents 分支。也就是說,setTimeout 中第一次執(zhí)行 setState 時,this.state.val1, 而 setState 完成打印后打印時 this.state.val 變成了2。第二次的 setState 同理。

前面介紹事務時,也提到了其在 React 源碼中的多處應用,像 initialize、perform、close、closeAll、motifyAll 等方法出現(xiàn)在調用棧中,都說明當前處于一個事務中。

既然事務這么有用,我們寫應用代碼時能使用它嗎?很可惜,答案是不能。盡管React不建議我們直接使用事務,但在 React 15.0 之前的版本中還是為開發(fā)者提供了 batchedUpdates 方法,它可以解決針對一開始例子中setTimeout 里的兩次 setState 導致兩次 render 的情況:

import ReactDOM, { unstable_batchedUpates } from 'teact-dom'

unstable_batchedUpates(() => {
  this.setState(val: this.state.val + 1)
  this.setState(val: this.state.val + 1)
})

React 15.0 以及之后版本中,已經(jīng)徹底將 batchUpdates 這個 API 移除了,因此不再建議開發(fā)者使用它。

到此,關于“React中setState的更新機制是什么”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續(xù)學習更多相關知識,請繼續(xù)關注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內容。

AI