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

資訊專欄INFORMATION COLUMN

useEffect中不能使用async緣由

3403771864 / 459人閱讀

  最近嘗試在 useEffect 使用 async 的時(shí)候會(huì)報(bào)錯(cuò),因此,本篇文章就是想喝大家說(shuō)說(shuō)為什么?也解讀其中緣由。

  具體代碼分析

  執(zhí)行 mountEffect

  當(dāng)頁(yè)面中使用 useEffect 的時(shí)候,會(huì)在初始化的時(shí)候執(zhí)行 mountEffect 如下:

  useEffect: function(create, deps) {
  currentHookNameInDev = "useEffect";
  mountHookTypesDev();
  checkDepsAreArrayDev(deps);
  return mountEffect(create, deps);
  },

  執(zhí)行 mountEffectImpl

  執(zhí)行 mountEffect 的時(shí)候執(zhí)行 mountEffectImpl 如下: 

 function mountEffectImpl(fiberFlags, hookFlags, create, deps) {
  var hook = mountWorkInProgressHook();
  var nextDeps = deps === void 0 ? null : deps;
  currentlyRenderingFiber$1.flags |= fiberFlags;
  hook.memoizedState = pushEffect(HasEffect | hookFlags, create, void 0, nextDeps);
  }

  執(zhí)行 pushEffect

  在 pushEffect 中會(huì)創(chuàng)建一個(gè) effect 節(jié)點(diǎn),也要哦添加到當(dāng)前函數(shù)對(duì)應(yīng) fiber 的 updateQueue 上面,數(shù)據(jù)結(jié)構(gòu)是一個(gè)環(huán)鏈。

  function pushEffect(tag, create, destroy, deps) {
  var effect = {
  tag,
  create,
  destroy,
  deps,
  next: null
  };
  var componentUpdateQueue = currentlyRenderingFiber$1.updateQueue;
  if (componentUpdateQueue === null) {
  componentUpdateQueue = createFunctionComponentUpdateQueue();
  currentlyRenderingFiber$1.updateQueue = componentUpdateQueue;
  componentUpdateQueue.lastEffect = effect.next = effect;
  } else {
  var lastEffect = componentUpdateQueue.lastEffect;
  if (lastEffect === null) {
  componentUpdateQueue.lastEffect = effect.next = effect;
  } else {
  var firstEffect = lastEffect.next;
  lastEffect.next = effect;
  effect.next = firstEffect;
  componentUpdateQueue.lastEffect = effect;
  }
  }
  return effect;
  }

  進(jìn)入到 schedulePassiveEffects

  直接忽略中間調(diào)度代碼內(nèi)容,進(jìn)入到 schedulePassiveEffects,這個(gè)函數(shù)作用是從函數(shù)組件對(duì)應(yīng)的 fiber 上獲取上面掛載的 effect,然后將 effect 和 fiber 堆到 pendingPassiveHookEffectsUnmount 和 pendingPassiveHookEffectsMount 這個(gè)兩個(gè)隊(duì)列中 

 function schedulePassiveEffects(finishedWork) {
  var updateQueue = finishedWork.updateQueue;
  var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;
  if (lastEffect !== null) {
  var firstEffect = lastEffect.next;
  var effect = firstEffect;
  do {
  var _effect = effect
  , next = _effect.next
  , tag = _effect.tag;
  if ((tag & Passive$1) !== NoFlags$1 && (tag & HasEffect) !== NoFlags$1) {
  //
  enqueuePendingPassiveHookEffectUnmount(finishedWork, effect);
  enqueuePendingPassiveHookEffectMount(finishedWork, effect);
  }
  effect = next;
  } while (effect !== firstEffect);
  }
  }

  推入卸載隊(duì)列

  這里是推入的邏輯,只展示推入掛載隊(duì)列的方法,推入卸載隊(duì)列是一樣的

  function enqueuePendingPassiveHookEffectMount(fiber, effect) {
  pendingPassiveHookEffectsMount.push(effect, fiber);
  if (!rootDoesHavePassiveEffects) {
  rootDoesHavePassiveEffects = true;
  scheduleCallback(NormalPriority$1, function() {
  flushPassiveEffects();
  return null;
  });
  }
  }

  invokePassiveEffectCreate 執(zhí)行

  早一大推度之后會(huì)進(jìn)入 flushPassiveEffectsImpl ,函數(shù)太長(zhǎng)了,只貼出相關(guān)的部分,邏輯是循環(huán)掛載 effect 隊(duì)列中的每一個(gè) effect 傳入到 invokePassiveEffectCreate 執(zhí)行

  // ...
  var mountEffects = pendingPassiveHookEffectsMount;
  pendingPassiveHookEffectsMount = [];
  for (var _i = 0; _i < mountEffects.length; _i += 2) {
  var _effect2 = mountEffects[_i];
  var _fiber = mountEffects[_i + 1];
  {
  setCurrentFiber(_fiber);
  {
  invokeGuardedCallback(null, invokePassiveEffectCreate, null, _effect2);
  }
  if (hasCaughtError()) {
  if (!(_fiber !== null)) {
  {
  throw Error("Should be working on an effect.");
  }
  }
  var _error4 = clearCaughtError();
  captureCommitPhaseError(_fiber, _error4);
  }
  resetCurrentFiber();
  }
  }
  // ...

  這個(gè)函數(shù)會(huì)獲取 create 并執(zhí)行,然后將執(zhí)行結(jié)果掛載到 destroy 上,這里的 create 就是 useEffect 中的第一個(gè)參數(shù),從這里可以看出,如果有返回值,那么 destroy 就是第一個(gè)函數(shù)的返回值,沒(méi)有就是 undefined

  function invokePassiveEffectCreate(effect) {
  var create = effect.create;
  effect.destroy = create();
  }

  卸載的時(shí)候會(huì)通過(guò)函數(shù)組件對(duì)應(yīng)的 fiber 獲取 effect 鏈表,然后遍歷鏈表,獲取環(huán)鏈上的每一個(gè)節(jié)點(diǎn),如果 destroy 不是 undefined 就執(zhí)行,所以如果 useEffect 第一個(gè)參數(shù)傳入 async, 那么這里的 destroy 就是一個(gè) promise 對(duì)象,對(duì)象是不能執(zhí)行的,所以報(bào)錯(cuò)。

  function commitHookEffectListUnmount(tag, finishedWork) {
  var updateQueue = finishedWork.updateQueue;
  var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;
  if (lastEffect !== null) {
  var firstEffect = lastEffect.next;
  var effect = firstEffect;
  do {
  if ((effect.tag & tag) === tag) {
  // Unmount
  var destroy = effect.destroy;
  effect.destroy = undefined;
  if (destroy !== undefined) {
  destroy();
  }
  }
  effect = effect.next;
  } while (effect !== firstEffect);
  }
  }

  知道解決方法,就好說(shuō)了,直接手寫(xiě)一個(gè)自定義 hook,包裹一下就可以處理這個(gè)問(wèn)題了,hook 實(shí)現(xiàn)如下。

  hook 實(shí)現(xiàn)

  import { useEffect } from 'react'
  export default function useAsyncEffect<T, U extends any[]>(
  method: () => Promise<T>,
  deps: U
  ) {
  useEffect(() => {
  (async () => {
  await method()
  })()
  }, deps)
  }

  使用

  import React, { useState } from 'react'
  import { useAsyncEffect } from './useAsyncEffect'
  export default function Demo() {
  const [count, setCount] = useState(0)
  function fetchData(): Promise<number> {
  return new Promise((resolve) => {
  setTimeout(() => {
  resolve(count + 1)
  }, 2000)
  })
  }
  useAsyncEffect(async () => {
  const count = await fetchData()
  setCount(count)
  }, [fetchData])
  return (
  <div>{count}</div>
  )
  }

  值得注意的是返回值永遠(yuǎn)是undefined,這就是留給大家開(kāi)動(dòng)腦筋解決。


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

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

相關(guān)文章

  • useEffect支持async及await如何運(yùn)用

    背景  在使用useEffect中用啦回調(diào)函數(shù)中使用 async...await... 這時(shí)候就會(huì)報(bào)錯(cuò)。  上面代碼可以看到,在報(bào)錯(cuò),effect function 應(yīng)該返回一個(gè)銷毀函數(shù)(effect:是指return返回的cleanup函數(shù)),如果 useEffect 第一個(gè)參數(shù)傳入 async,返回值則變成了 Promise,結(jié)果就是會(huì)導(dǎo)致 react 在調(diào)用銷毀函數(shù)的時(shí)候報(bào)錯(cuò)?! eact...

    3403771864 評(píng)論0 收藏0
  • React Hooks 入門(mén)(2019)

    摘要:到目前為止,表達(dá)這種流程的基本形式是課程。按鈕依次響應(yīng)并更改獲取更新的文本。事實(shí)證明不能從返回一個(gè)。可以在組件中使用本地狀態(tài),而無(wú)需使用類。替換了提供統(tǒng)一,和。另一方面,跟蹤中的狀態(tài)變化確實(shí)很難。 備注:為了保證的可讀性,本文采用意譯而非直譯。 在這個(gè) React鉤子 教程中,你將學(xué)習(xí)如何使用 React鉤子,它們是什么,以及我們?yōu)槭裁催@樣做! showImg(https://segm...

    GitCafe 評(píng)論0 收藏0
  • 在 React Hooks 如何請(qǐng)求數(shù)據(jù)?

    摘要:現(xiàn)在,請(qǐng)求數(shù)據(jù)和查詢參數(shù)兩個(gè)相互獨(dú)立,但是我們需要像一個(gè)辦法希望他們耦合起來(lái),只獲取輸入框輸入的參數(shù)指定的話題文章。好了,現(xiàn)在一旦你改變輸入框內(nèi)容,數(shù)據(jù)就會(huì)重新獲取。 showImg(https://segmentfault.com/img/remote/1460000018652592?w=1024&h=683); 通過(guò)這個(gè)教程,我想告訴你在 React 中如何使用 state 和 ...

    snowell 評(píng)論0 收藏0
  • 淺談React Hooks

    摘要:另外也不利于組件的,及。所以在使用時(shí),盡量將相關(guān)聯(lián)的,會(huì)共同變化的值放入一個(gè)。有同學(xué)可能會(huì)想,每次后都會(huì)執(zhí)行,這樣會(huì)不會(huì)對(duì)性能造成影響。另外必須以開(kāi)頭來(lái)命名,這樣工具才能正確檢測(cè)其是否符合規(guī)范。 由于工作的原因我已經(jīng)很長(zhǎng)時(shí)間沒(méi)接觸過(guò)React了。前段時(shí)間圈子里都在討論React Hooks,出于好奇也學(xué)習(xí)了一番,特此整理以加深理解。 緣由 在web應(yīng)用無(wú)所不能的9012年,組成應(yīng)用的C...

    yearsj 評(píng)論0 收藏0
  • 「每日一瞥

    摘要:首先,我們需要一個(gè)基本框架來(lái)處理表單域變化和表格提交。最起碼我們需要提供一個(gè)來(lái)告訴如果用戶還沒(méi)有對(duì)表單域進(jìn)行改動(dòng),就不必展示錯(cuò)誤。我們需要一個(gè)來(lái)標(biāo)識(shí)用戶已嘗試提交表單,還需要來(lái)標(biāo)識(shí)表單是否正在提交以及每個(gè)表單域是否正在進(jìn)行異步校驗(yàn)。 showImg(https://segmentfault.com/img/remote/1460000017516912?w=1200&h=630); ...

    XboxYan 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<