国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

【React深入】setState的執(zhí)行機(jī)制

zombieda / 2529人閱讀

摘要:調(diào)用事務(wù)的方法,遍歷待更新組件隊(duì)列依次執(zhí)行更新。執(zhí)行生命周期,根據(jù)返回值判斷是否要繼續(xù)更新。三總結(jié)鉤子函數(shù)和合成事件中在的生命周期和合成事件中,仍然處于他的更新機(jī)制中,這時(shí)為。這時(shí)將執(zhí)行之前累積的。

一.幾個(gè)開發(fā)中經(jīng)常會遇到的問題

以下幾個(gè)問題是我們在實(shí)際開發(fā)中經(jīng)常會遇到的場景,下面用幾個(gè)簡單的示例代碼來還原一下。

1.setState是同步還是異步的,為什么有的時(shí)候不能立即拿到更新結(jié)果而有的時(shí)候可以? 1.1 鉤子函數(shù)和React合成事件中的setState

現(xiàn)在有兩個(gè)組件

  componentDidMount() {
    console.log("parent componentDidMount");
  }

  render() {
    return (
      
); }

組件內(nèi)部放入同樣的代碼,并在Setstate1中的componentDidMount中放入一段同步延時(shí)代碼,打印延時(shí)時(shí)間:

  componentWillUpdate() {
    console.log("componentWillUpdate");
  }

  componentDidUpdate() {
    console.log("componentDidUpdate");
  }

  componentDidMount() {
    console.log("SetState調(diào)用setState");
    this.setState({
      index: this.state.index + 1
    })
    console.log("state", this.state.index);
    
    console.log("SetState調(diào)用setState");
    this.setState({
      index: this.state.index + 1
    })
    console.log("state", this.state.index);
  }

下面是執(zhí)行結(jié)果:

說明:

1.調(diào)用setState不會立即更新

2.所有組件使用的是同一套更新機(jī)制,當(dāng)所有組件didmount后,父組件didmount,然后執(zhí)行更新

3.更新時(shí)會把每個(gè)組件的更新合并,每個(gè)組件只會觸發(fā)一次更新的生命周期。

1.2 異步函數(shù)和原生事件中的setstate

setTimeout中調(diào)用setState(例子和在瀏覽器原生事件以及接口回調(diào)中執(zhí)行效果相同)

  componentDidMount() {
    setTimeout(() => {
      console.log("調(diào)用setState");
      this.setState({
        index: this.state.index + 1
      })
      console.log("state", this.state.index);
      console.log("調(diào)用setState");
      this.setState({
        index: this.state.index + 1
      })
      console.log("state", this.state.index);
    }, 0);
  }

執(zhí)行結(jié)果:

說明:

1.在父組件didmount后執(zhí)行

2.調(diào)用setState同步更新

2.為什么有時(shí)連續(xù)兩次setState只有一次生效?

分別執(zhí)行以下代碼:

  componentDidMount() {
    this.setState({ index: this.state.index + 1 }, () => {
      console.log(this.state.index);
    })
    this.setState({ index: this.state.index + 1 }, () => {
      console.log(this.state.index);
    })
  }
  componentDidMount() {
    this.setState((preState) => ({ index: preState.index + 1 }), () => {
      console.log(this.state.index);
    })
    this.setState(preState => ({ index: preState.index + 1 }), () => {
      console.log(this.state.index);
    })
  }

執(zhí)行結(jié)果:

1
1
2
2

說明:

1.直接傳遞對象的setstate會被合并成一次

2.使用函數(shù)傳遞state不會被合并

二.setState執(zhí)行過程

由于源碼比較復(fù)雜,就不貼在這里了,有興趣的可以去githubclone一份然后按照下面的流程圖去走一遍。

1.流程圖

圖不清楚可以點(diǎn)擊查看原圖

partialStatesetState傳入的第一個(gè)參數(shù),對象或函數(shù)

_pendingStateQueue:當(dāng)前組件等待執(zhí)行更新的state隊(duì)列

isBatchingUpdates:react用于標(biāo)識當(dāng)前是否處于批量更新狀態(tài),所有組件公用

dirtyComponent:當(dāng)前所有處于待更新狀態(tài)的組件隊(duì)列

transcation:react的事務(wù)機(jī)制,在被事務(wù)調(diào)用的方法外包裝n個(gè)waper對象,并一次執(zhí)行:waper.init、被調(diào)用方法、waper.close

FLUSH_BATCHED_UPDATES:用于執(zhí)行更新的waper,只有一個(gè)close方法

2.執(zhí)行過程

對照上面流程圖的文字說明,大概可分為以下幾步:

1.將setState傳入的partialState參數(shù)存儲在當(dāng)前組件實(shí)例的state暫存隊(duì)列中。

2.判斷當(dāng)前React是否處于批量更新狀態(tài),如果是,將當(dāng)前組件加入待更新的組件隊(duì)列中。

3.如果未處于批量更新狀態(tài),將批量更新狀態(tài)標(biāo)識設(shè)置為true,用事務(wù)再次調(diào)用前一步方法,保證當(dāng)前組件加入到了待更新組件隊(duì)列中。

4.調(diào)用事務(wù)的waper方法,遍歷待更新組件隊(duì)列依次執(zhí)行更新。

5.執(zhí)行生命周期componentWillReceiveProps

6.將組件的state暫存隊(duì)列中的state進(jìn)行合并,獲得最終要更新的state對象,并將隊(duì)列置為空。

7.執(zhí)行生命周期componentShouldUpdate,根據(jù)返回值判斷是否要繼續(xù)更新。

8.執(zhí)行生命周期componentWillUpdate

9.執(zhí)行真正的更新,render

10.執(zhí)行生命周期componentDidUpdate

三.總結(jié) 1.鉤子函數(shù)和合成事件中:

react的生命周期和合成事件中,react仍然處于他的更新機(jī)制中,這時(shí)isBranchUpdate為true。

按照上述過程,這時(shí)無論調(diào)用多少次setState,都會不會執(zhí)行更新,而是將要更新的state存入_pendingStateQueue,將要更新的組件存入dirtyComponent

當(dāng)上一次更新機(jī)制執(zhí)行完畢,以生命周期為例,所有組件,即最頂層組件didmount后會將isBranchUpdate設(shè)置為false。這時(shí)將執(zhí)行之前累積的setState

2.異步函數(shù)和原生事件中

由執(zhí)行機(jī)制看,setState本身并不是異步的,而是如果在調(diào)用setState時(shí),如果react正處于更新過程,當(dāng)前更新會被暫存,等上一次更新執(zhí)行后在執(zhí)行,這個(gè)過程給人一種異步的假象。

在生命周期,根據(jù)JS的異步機(jī)制,會將異步函數(shù)先暫存,等所有同步代碼執(zhí)行完畢后在執(zhí)行,這時(shí)上一次更新過程已經(jīng)執(zhí)行完畢,isBranchUpdate被設(shè)置為false,根據(jù)上面的流程,這時(shí)再調(diào)用setState即可立即執(zhí)行更新,拿到更新結(jié)果。

3.partialState合并機(jī)制

我們看下流程中_processPendingState的代碼,這個(gè)函數(shù)是用來合并state暫存隊(duì)列的,最后返回一個(gè)合并后的state

  _processPendingState: function (props, context) {
    var inst = this._instance;
    var queue = this._pendingStateQueue;
    var replace = this._pendingReplaceState;
    this._pendingReplaceState = false;
    this._pendingStateQueue = null;

    if (!queue) {
      return inst.state;
    }

    if (replace && queue.length === 1) {
      return queue[0];
    }

    var nextState = _assign({}, replace ? queue[0] : inst.state);
    for (var i = replace ? 1 : 0; i < queue.length; i++) {
      var partial = queue[i];
      _assign(nextState, typeof partial === "function" ? partial.call(inst, nextState, props, context) : partial);
    }

    return nextState;
  },

我們只需要關(guān)注下面這段代碼:

 _assign(nextState, typeof partial === "function" ? partial.call(inst, nextState, props, context) : partial);

如果傳入的是對象,很明顯會被合并成一次:

Object.assign(
  nextState,
  {index: state.index+ 1},
  {index: state.index+ 1}
)

如果傳入的是函數(shù),函數(shù)的參數(shù)preState是前一次合并后的結(jié)果,所以計(jì)算結(jié)果是準(zhǔn)確的。

4.componentDidMount調(diào)用setstate
在componentDidMount()中,你 可以立即調(diào)用setState()。它將會觸發(fā)一次額外的渲染,但是它將在瀏覽器刷新屏幕之前發(fā)生。這保證了在此情況下即使render()將會調(diào)用兩次,用戶也不會看到中間狀態(tài)。謹(jǐn)慎使用這一模式,因?yàn)樗?dǎo)致性能問題。在大多數(shù)情況下,你可以 在constructor()中使用賦值初始狀態(tài)來代替。然而,有些情況下必須這樣,比如像模態(tài)框和工具提示框。這時(shí),你需要先測量這些DOM節(jié)點(diǎn),才能渲染依賴尺寸或者位置的某些東西。

以上是官方文檔的說明,不推薦直接在componentDidMount直接調(diào)用setState,由上面的分析:componentDidMount本身處于一次更新中,我們又調(diào)用了一次setState,就會在未來再進(jìn)行一次render,造成不必要的性能浪費(fèi),大多數(shù)情況可以設(shè)置初始值來搞定。

當(dāng)然在componentDidMount我們可以調(diào)用接口,再回調(diào)中去修改state,這是正確的做法。

當(dāng)state初始值依賴dom屬性時(shí),在componentDidMountsetState是無法避免的。

5.componentWillUpdate componentDidUpdate

這兩個(gè)生命周期中不能調(diào)用setState

由上面的流程圖很容易發(fā)現(xiàn),在它們里面調(diào)用setState會造成死循環(huán),導(dǎo)致程序崩潰。

6.推薦使用方式

在調(diào)用setState時(shí)使用函數(shù)傳遞state值,在回調(diào)函數(shù)中獲取最新更新后的state

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/102018.html

相關(guān)文章

  • ReactsetState幾個(gè)現(xiàn)象---先知道再理解

    摘要:原生事件中的在按鈕原生事件中定義的和定時(shí)器效果一樣,每次都會引起新的事件是合并的成一次的。原生事件事件生成計(jì)時(shí)器點(diǎn)擊按鈕,先執(zhí)行原生事件,再執(zhí)行事件,但是原生事件會觸發(fā)兩次,事件觸發(fā)一次。 常規(guī)情況 在同一個(gè)方法中多次setState是會被合并的,并且對相同屬性的設(shè)置只保留最后一次的設(shè)置; import React from react; export class Test exte...

    tomlingtm 評論0 收藏0
  • 深入React技術(shù)棧之setState詳解

    摘要:除此之外指的是繞過通過直接添加的事件處理函數(shù)和產(chǎn)生的異步調(diào)用。但是,當(dāng)在調(diào)用事件處理函數(shù)之前就會調(diào)用,這個(gè)函數(shù)會把修改為,造成的后果就是由控制的事件處理過程不會同步更新。 拋出問題 class Example extends Component { contructor () { super() this.state = { value: 0, ...

    leeon 評論0 收藏0
  • 深入React技術(shù)棧之setState詳解

    摘要:除此之外指的是繞過通過直接添加的事件處理函數(shù)和產(chǎn)生的異步調(diào)用。但是,當(dāng)在調(diào)用事件處理函數(shù)之前就會調(diào)用,這個(gè)函數(shù)會把修改為,造成的后果就是由控制的事件處理過程不會同步更新。 拋出問題 class Example extends Component { contructor () { super() this.state = { value: 0, ...

    TNFE 評論0 收藏0
  • setState異步、同步與進(jìn)階

    摘要:根本原因在于,并不是真正意義上的異步操作,它只是模擬了異步的行為。而合成事件和生命周期函數(shù)中,是受控制的,其會將設(shè)置為,從而走的是類似異步的那一套。總結(jié)此處總結(jié)是直接引用了只在合成事件和鉤子函數(shù)中是異步的,在原生事件和中都是同步的。 如何使用setState 在 React 日常的使用中,一個(gè)很重要的點(diǎn)就是,不要直接去修改 state。例如:this.state.count = 1是無...

    widuu 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<