<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          由螞蟻面試題聊聊setState的用法

          共 3664字,需瀏覽 8分鐘

           ·

          2021-03-17 02:44

          面螞蟻的時(shí)候,面試官問(wèn)了這么一個(gè)問(wèn)題,你從不會(huì)用setState到會(huì)使用它,經(jīng)歷哪些階段,實(shí)際開(kāi)發(fā)中需要注意得點(diǎn)是什么呢?

          回答完上面這個(gè)問(wèn)題,順便聊了下setState同步還是異步的問(wèn)題。

          setState是同步還是異步?

          首先,這個(gè)問(wèn)題的拋出,我會(huì)想為什么要拋出這個(gè)問(wèn)題呢?如果說(shuō),你需要依賴(lài)狀態(tài)更新后的值時(shí),那么首先如何做呢?

          • 對(duì)于Class Component而言,我們可以在componentDidMount或者是componentDidUpdate階段來(lái)執(zhí)行。
          • 對(duì)于Function Component而言,我們可以在useEffect的回調(diào)函數(shù)中執(zhí)行。

          首先,我們先給出結(jié)論,在React中不同的模式它的情況是不一樣的,主要拿兩種模式來(lái)說(shuō)。

          1. legacy模式
          2. concurrent模式

          legacy 模式

          這是當(dāng)前 React app 使用的方式??

          ReactDOM.render(<App />, rootNode)

          當(dāng)前沒(méi)有計(jì)劃刪除本模式,但是這個(gè)模式可能不支持這些新功能。

          回到我們上述的問(wèn)題,setState是同步的還是異步的?

          當(dāng)在legacy模式下,命中batchedUpdates時(shí),setState是異步的。

          當(dāng)在legacy模式下,沒(méi)命中batchedUpdates時(shí),setState是同步的。

          既然聊到了這里,我們來(lái)說(shuō)一說(shuō)batchedUpdates函數(shù)的作用。

          那么它是干嘛的呢?如果你在處理邏輯函數(shù)中多次調(diào)用this.setState時(shí),它是如何更新?tīng)顟B(tài)的呢?

              this.setState({
          value: this.state.value + 1
          })
          this.setState({
          value: this.state.value + 1
          })
          this.setState({
          value: this.state.value + 1
          })

          那React實(shí)現(xiàn)了這個(gè)批量更新的操作,將多次的setState合并為一次更新,那么它是如何實(shí)現(xiàn)的呢?batchedUpdates函數(shù)就登場(chǎng)了。

          function batchedUpdates$1(fn, a) {
          var prevExecutionContext = executionContext;
          executionContext |= BatchedContext;

          try {
          return fn(a);
          } finally {
          executionContext = prevExecutionContext;

          if (executionContext === NoContext) {
          // Flush the immediate callbacks that were scheduled during this batch
          resetRenderTimer();
          flushSyncCallbackQueue(); // 同步的更新
          }
          }
          }

          這個(gè)函數(shù)會(huì)傳遞一個(gè)fn,當(dāng)執(zhí)行fn之前,會(huì)在executionContext變量上附加一個(gè)BatchedContext,當(dāng)fn執(zhí)行完畢后,executionContext就會(huì)把之前的BatchedContext標(biāo)記給去除掉。

          • 這樣子一來(lái),當(dāng)executionContext帶上了BatchedContext標(biāo)記的話,react內(nèi)部就會(huì)去做判斷,帶上了這個(gè)標(biāo)記,這次的更新就是批處理,那么此次更新就是異步的。

          那么,我們是不是能夠假設(shè)一下,如果在執(zhí)行完fn函數(shù)后,再去更新?tīng)顟B(tài)的話,是不是就能完成同步的更新呢?

          setTimeout函數(shù),我們可以把setState放在定時(shí)器中,這樣子一來(lái)的話,當(dāng)fn函數(shù)執(zhí)行完時(shí),BatchedContext標(biāo)記也去掉了,然后等到 setTimeout 的回調(diào)函數(shù)等到空閑被執(zhí)行的時(shí)候,才會(huì)執(zhí)行 setState。

          		setTimeout(() => {
          this.setState({ value: this.state.value + 1})
          }, 0)

          這也就是當(dāng)executionContext === NoContext,也就是會(huì)執(zhí)行flushSyncCallbackQueue函數(shù),完成此次的同步更新。

          當(dāng)然了,在concurrent 模式下,又是有所不同的。

          這個(gè)時(shí)候,我們得談一談scheduleUpdateOnFiber函數(shù)。

          我們都知道任務(wù)調(diào)度的起點(diǎn)是 scheduleUpdateOnFiber 方法,React.render、setState、forceUpdate、React Hooks 的dispatchAction 都會(huì)經(jīng)過(guò) scheduleUpdateOnFiber。

          function scheduleUpdateOnFiber(fiber, lane, eventTime) {
          // ...
          if (root === workInProgressRoot) {
          // ......
          } // TO an argument to that function and this one.
          if (lane === SyncLane) { // 同步任務(wù)
          if ( // 檢查當(dāng)前是不是在unbatchedUpdates(非批量更新),(初次渲染的ReactDOM.render就是unbatchedUpdates)
          (executionContext & LegacyUnbatchedContext) !== NoContext && // Check if we're not already rendering
          (executionContext & (RenderContext | CommitContext)) === NoContext) {
          // Register pending interactions on the root to avoid losing traced interaction data.
          schedulePendingInteractions(root, lane);
          performSyncWorkOnRoot(root);
          } else {
          ensureRootIsScheduled(root, eventTime);
          schedulePendingInteractions(root, lane);
          if (executionContext === NoContext) {
          resetRenderTimer();
          flushSyncCallbackQueue();
          }
          }
          } else { // 異步任務(wù)
          // concurrent模式下是跳過(guò)了 flushSyncCallbackQueue 同步更新
          // ....
          }
          }

          scheduleUpdateOnFiber函數(shù)通過(guò)lane === SyncLane來(lái)判斷是同步任務(wù)還是異步任務(wù),我們通過(guò)ReactDom.render()方式創(chuàng)建的React app是會(huì)進(jìn)入這個(gè)判斷的,而concurrent模式下,則不同,那么它是如何創(chuàng)建的呢??

          concurrent 模式

          你可以理解成,這個(gè)暫時(shí)還是實(shí)驗(yàn)階段,當(dāng)未來(lái)穩(wěn)定后,將會(huì)作為React開(kāi)發(fā)的默認(rèn)開(kāi)發(fā)模式,它是如何創(chuàng)建一個(gè)React App應(yīng)用的呢??

          ReactDOM.createRoot(rootNode).render(<App />)

          這個(gè)模式開(kāi)啟了所有的新功能。

          concurrent模式下?tīng)顟B(tài)的更新都是異步的。

          關(guān)于React的concurrent 模式解讀,有興趣可以看看官方文檔。

          到這里的話,似乎我們對(duì)React中setState是同步的還是異步的就有所了解了。

          哪些會(huì)命中batchUpdate機(jī)制

          • 生命周期(和它調(diào)用函數(shù))
          • React中注冊(cè)的事件
          • React可以'管理入口'

           感謝大家

          1. 關(guān)注「前端UpUp」,分享精選面試熱點(diǎn)文章。

          2. 加我好友,一起討論算法,2021一起UpUp。

          瀏覽 66
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  免费高清无码在线观看 | 少妇激情五月天 | 久久久久久国产精品 | 亚洲最大的黄色网址 | 网站自拍视频网站在线看 |