關(guān)于this.setState()的那些事

在網(wǎng)上看了很多關(guān)于this.setState()的介紹,覺得受益匪淺,就總結(jié)了一些幫助自己理解的點(diǎn),在此分享出來,如果有侵權(quán)的地方,請(qǐng)及時(shí)提醒。

一、State的定義

狀態(tài)(state) 和 屬性(props) 類似,都是一個(gè)組件所需要的一些數(shù)據(jù)集合,但是它是私有的,并且由組件本身完全控制,可以認(rèn)為它是組件的“私有屬性(或者是局部屬性)”。

二、關(guān)于 setState() 有三件事是你應(yīng)該知道的。# 參考鏈接

1.不要直接修改 state(狀態(tài))

this.state.comment = 'Hello';

上述代碼并不會(huì)重新渲染組件,需要使用this.setState()代替:

this.setState({
  comment: 'Hello'
});

需要注意的是唯一可以分配 this.state 的地方是構(gòu)造函數(shù)

2.state(狀態(tài)) 更新可能是異步的

React 為了優(yōu)化性能,有可能會(huì)將多個(gè) setState() 調(diào)用合并為一次更新。
因?yàn)?code>this.props和this.state 可能是異步更新的,你不能依賴他們的值計(jì)算下一個(gè)state(狀態(tài))。以下面的代碼為例:

this.setState({
  counter: this.state.counter + this.props.increment,
});

我們并不能通過上述代碼得到想要的值,為了彌補(bǔ)這個(gè)問題,使用另一種 setState() 的形式,接受一個(gè)函數(shù)。這個(gè)函數(shù)將接收前一個(gè)狀態(tài)作為第一個(gè)參數(shù),應(yīng)用更新時(shí)的 props 作為第二個(gè)參數(shù),代碼如下:

this.setState((prevState, props) => ({
  counter: prevState.counter + props.increment
}));

3.state(狀態(tài))更新會(huì)被合并

當(dāng)你調(diào)用 setState(), React 將合并你提供的對(duì)象到當(dāng)前的狀態(tài)中。所以當(dāng)State是一個(gè)多鍵值的結(jié)構(gòu)時(shí),可以單獨(dú)更新其中的一個(gè),此時(shí)會(huì)進(jìn)行“差分”更新,不會(huì)影響其他的屬性值。

三、setState()的異步更新。# 原文鏈接

1.執(zhí)行setState()之后干了什么?

setState()方法通過一個(gè)隊(duì)列機(jī)制實(shí)現(xiàn)state更新,當(dāng)執(zhí)行setState()的時(shí)候,會(huì)將需要更新的state合并之后放入狀態(tài)隊(duì)列,而不會(huì)立即更新this.state(可以和瀏覽器的事件隊(duì)列類比)。如果我們不使用setState而是使用this.state.key來修改,將不會(huì)觸發(fā)組件的re-render。如果將this.state賦值給一個(gè)新的對(duì)象引用,那么其他不在對(duì)象上的state將不會(huì)被放入狀態(tài)隊(duì)列中,當(dāng)下次調(diào)用setState()并對(duì)狀態(tài)隊(duì)列進(jìn)行合并時(shí),直接造成了state丟失。

2.setState()可以接受一個(gè)函數(shù)作為參數(shù)?

setState() 不僅能夠接受一個(gè)對(duì)象作為參數(shù),還能夠接受一個(gè)函數(shù)作為參數(shù)。函數(shù)的參數(shù)即為 state 的前一個(gè)狀態(tài)以及 props
React文檔中對(duì)setState的說明如下:

void setState (
      function|object nextState,
      [function callback]
)

上述代碼的第二個(gè)參數(shù)是一個(gè)回調(diào)函數(shù),在setState() 的異步操作結(jié)束并且組件已經(jīng)重新渲染的時(shí)候執(zhí)行。換句話說,我們可以通過這個(gè)回調(diào)來拿到更新的state的值。

3.執(zhí)行setState()后能拿到最新的state值嗎?

以前在寫代碼時(shí)候,總是遇到明明執(zhí)行過setState(),但是state的值卻不是最新的,那么如何解決這個(gè)問題呢?

因?yàn)?code>setState()函數(shù)接受兩個(gè)參數(shù),一個(gè)是一個(gè)對(duì)象,就是設(shè)置的狀態(tài),還有一個(gè)是一個(gè)回調(diào)函數(shù),是在設(shè)置狀態(tài)成功之后執(zhí)行的,所以我們可以通過回掉拿到最新的state值。代碼如下:

updateData = (newData) => {
    this.setState(
        { data: newData },
        () => {
            //這里打印的是最新的state值
            console.log(this.state.data);
        }
    );
}

4.setState()一定是異步更新嗎? **# 原文鏈接

我們先來看看下面的代碼:

function incrementMultiple() {
      this.setState({count: this.state.count + 1});
      this.setState({count: this.state.count + 1});
      this.setState({count: this.state.count + 1});
}

直觀上來看,當(dāng)上面的 incrementMultiple 函數(shù)被調(diào)用時(shí),組件狀態(tài)的 count 值被增加了3次,每次增加1,那最后 count 被增加了3。但是,實(shí)際上的結(jié)果只給 state 增加了1。
事實(shí)上,setState 方法與包含在其中的執(zhí)行是一個(gè)很復(fù)雜的過程,從 React 最初的版本到現(xiàn)在,也有無數(shù)次的修改。它的工作除了要更動(dòng) this.state 之外,還要負(fù)責(zé)觸發(fā)重新渲染,這里面要經(jīng)過 React 核心 diff 算法,最終才能決定是否要進(jìn)行重渲染,以及如何渲染。而且為了批次與效能的理由,多個(gè) setState 呼叫有可能在執(zhí)行過程中還需要被合并,所以它被設(shè)計(jì)以延時(shí)的來進(jìn)行執(zhí)行是相當(dāng)合理的。

setState執(zhí)行過程

在 React 的 setState 函數(shù)實(shí)現(xiàn)中,會(huì)根據(jù)一個(gè)變量 isBatchingUpdates 判斷是直接更新 this.state 還是放到隊(duì)列中回頭再說,而 isBatchingUpdates 默認(rèn)是 false,也就表示 setState 會(huì)同步更新 this.state,但是,有一個(gè)函數(shù) batchedUpdates,這個(gè)函數(shù)會(huì)把 isBatchingUpdates 修改為 true,而當(dāng) React 在調(diào)用事件處理函數(shù)之前就會(huì)調(diào)用這個(gè) batchedUpdates,造成的后果,就是由 React 控制的事件處理過程 setState 不會(huì)同步更新 this.state。

作者給出了下面的重點(diǎn),趕緊拿起我的小本本記下。

由 React 控制的事件處理過程 setState 不會(huì)同步更新 this.state!
也就是說,在 React 控制之外的情況, setState 會(huì)同步更新 this.state!

在大部分的使用情況下,我們都是使用了 React 庫(kù)中的表單組件,例如 select、input、button 等等,它們都是 React 庫(kù)中人造的組件與事件,是處于 React 庫(kù)的控制之下,比如組件原色 onClick 都是經(jīng)過 React 包裝。在這個(gè)情況下,setState 就會(huì)以異步的方式執(zhí)行。

總結(jié)就到這里了,由于我是技術(shù)渣渣,能看懂和理解的只有這么多了,如果有讀者還想了解更多的內(nèi)容,可以點(diǎn)擊我文中的原文鏈接去看原作者的文章,如果遇到侵權(quán)的地方,請(qǐng)聯(lián)系我,必刪。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 說在前面 關(guān)于 react 的總結(jié)過去半年就一直碎碎念著要搞起來,各(wo)種(tai)原(lan)因(le)。心...
    陳嘻嘻啊閱讀 7,027評(píng)論 7 41
  • HTML模版 之后出現(xiàn)的React代碼嵌套入模版中。 1. Hello world 這段代碼將一個(gè)一級(jí)標(biāo)題插入到指...
    ryanho84閱讀 6,430評(píng)論 0 9
  • 本筆記基于React官方文檔,當(dāng)前React版本號(hào)為15.4.0。 1. 安裝 1.1 嘗試 開始之前可以先去co...
    Awey閱讀 7,927評(píng)論 14 128
  • 相關(guān)知識(shí) 在租房這方面,房屋中介其實(shí)分為中介和代理兩種。 中介:幫你找來大量的客戶,你選擇客戶,你和客戶簽訂租賃合...
    FifiZhuang閱讀 280評(píng)論 2 0
  • 很多年后,每當(dāng)抬頭仰望天空,小飛總會(huì)想起爺爺。 大雪下的緊,村莊白茫茫一片,天變得暗了,冷風(fēng)呼嘯著...
    行律閱讀 490評(píng)論 0 1

友情鏈接更多精彩內(nèi)容