亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

useEffect支持async及await使用方式

 更新時(shí)間:2022年07月11日 10:13:19   作者:Gopal  
這篇文章主要為大家介紹了useEffect支持async及await的使用方式示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

引言

本文是深入淺出 ahooks 源碼系列文章的第六篇,這個(gè)系列的目標(biāo)主要有以下幾點(diǎn):

  • 加深對(duì) React hooks 的理解。
  • 學(xué)習(xí)如何抽象自定義 hooks。構(gòu)建屬于自己的 React hooks 工具庫(kù)。
  • 培養(yǎng)閱讀學(xué)習(xí)源碼的習(xí)慣,工具庫(kù)是一個(gè)對(duì)源碼閱讀不錯(cuò)的選擇。

注:本系列對(duì) ahooks 的源碼解析是基于 v3.3.13。自己 folk 了一份源碼,主要是對(duì)源碼做了一些解讀,可見(jiàn) 詳情。

背景

大家在使用 useEffect 的時(shí)候,假如回調(diào)函數(shù)中使用 async...await... 的時(shí)候,會(huì)報(bào)錯(cuò)如下。

看報(bào)錯(cuò),我們知道 effect function 應(yīng)該返回一個(gè)銷(xiāo)毀函數(shù)(effect:是指return返回的cleanup函數(shù)),如果 useEffect 第一個(gè)參數(shù)傳入 async,返回值則變成了 Promise,會(huì)導(dǎo)致 react 在調(diào)用銷(xiāo)毀函數(shù)的時(shí)候報(bào)錯(cuò)。

React 為什么要這么做?

useEffect 作為 Hooks 中一個(gè)很重要的 Hooks,可以讓你在函數(shù)組件中執(zhí)行副作用操作。 它能夠完成之前 Class Component 中的生命周期的職責(zé)。它返回的函數(shù)的執(zhí)行時(shí)機(jī)如下:

  • 首次渲染不會(huì)進(jìn)行清理,會(huì)在下一次渲染,清除上一次的副作用。
  • 卸載階段也會(huì)執(zhí)行清除操作。

不管是哪個(gè),我們都不希望這個(gè)返回值是異步的,這樣我們無(wú)法預(yù)知代碼的執(zhí)行情況,很容易出現(xiàn)難以定位的 Bug。所以 React 就直接限制了不能 useEffect 回調(diào)函數(shù)中不能支持 async...await...

useEffect 怎么支持 async...await...

竟然 useEffect 的回調(diào)函數(shù)不能使用 async...await,那我直接在它內(nèi)部使用。

做法一:創(chuàng)建一個(gè)異步函數(shù)(async...await 的方式),然后執(zhí)行該函數(shù)。

useEffect(() => {
  const asyncFun = async () => {
    setPass(await mockCheck());
  };
  asyncFun();
}, []);

做法二:也可以使用 IIFE,如下所示:

useEffect(() => {
  (async () => {
    setPass(await mockCheck());
  })();
}, []);

自定義 hooks

既然知道了怎么解決,我們完全可以將其封裝成一個(gè) hook,讓使用更加的優(yōu)雅。我們來(lái)看下 ahooks 的 useAsyncEffect,它支持所有的異步寫(xiě)法,包括 generator function。

思路跟上面一樣,入?yún)⒏?useEffect 一樣,一個(gè)回調(diào)函數(shù)(不過(guò)這個(gè)回調(diào)函數(shù)支持異步),另外一個(gè)依賴(lài)項(xiàng) deps。內(nèi)部還是 useEffect,將異步的邏輯放入到它的回調(diào)函數(shù)里面。

function useAsyncEffect(
  effect: () => AsyncGenerator<void, void, void> | Promise<void>,
  // 依賴(lài)項(xiàng)
  deps?: DependencyList,
) {
  // 判斷是 AsyncGenerator
  function isAsyncGenerator(
    val: AsyncGenerator<void, void, void> | Promise<void>,
  ): val is AsyncGenerator<void, void, void> {
    // Symbol.asyncIterator: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol/asyncIterator
    // Symbol.asyncIterator 符號(hào)指定了一個(gè)對(duì)象的默認(rèn)異步迭代器。如果一個(gè)對(duì)象設(shè)置了這個(gè)屬性,它就是異步可迭代對(duì)象,可用于for await...of循環(huán)。
    return isFunction(val[Symbol.asyncIterator]);
  }
  useEffect(() => {
    const e = effect();
    // 這個(gè)標(biāo)識(shí)可以通過(guò) yield 語(yǔ)句可以增加一些檢查點(diǎn)
    // 如果發(fā)現(xiàn)當(dāng)前 effect 已經(jīng)被清理,會(huì)停止繼續(xù)往下執(zhí)行。
    let cancelled = false;
    // 執(zhí)行函數(shù)
    async function execute() {
      // 如果是 Generator 異步函數(shù),則通過(guò) next() 的方式全部執(zhí)行
      if (isAsyncGenerator(e)) {
        while (true) {
          const result = await e.next();
          // Generate function 全部執(zhí)行完成
          // 或者當(dāng)前的 effect 已經(jīng)被清理
          if (result.done || cancelled) {
            break;
          }
        }
      } else {
        await e;
      }
    }
    execute();
    return () => {
      // 當(dāng)前 effect 已經(jīng)被清理
      cancelled = true;
    };
  }, deps);
}

async...await 我們之前已經(jīng)提到了,重點(diǎn)看看實(shí)現(xiàn)中變量 cancelled 的實(shí)現(xiàn)的功能。 它的作用是中斷執(zhí)行。

通過(guò) yield 語(yǔ)句可以增加一些檢查點(diǎn),如果發(fā)現(xiàn)當(dāng)前 effect 已經(jīng)被清理,會(huì)停止繼續(xù)往下執(zhí)行。

試想一下,有一個(gè)場(chǎng)景,用戶(hù)頻繁的操作,可能現(xiàn)在這一輪操作 a 執(zhí)行還沒(méi)完成,就已經(jīng)開(kāi)始開(kāi)始下一輪操作 b。這個(gè)時(shí)候,操作 a 的邏輯已經(jīng)失去了作用了,那么我們就可以停止往后執(zhí)行,直接進(jìn)入下一輪操作 b 的邏輯執(zhí)行。這個(gè) cancelled 就是用來(lái)取消當(dāng)前正在執(zhí)行的一個(gè)標(biāo)識(shí)符。

還可以支持 useEffect 的清除機(jī)制么?

可以看到上面的 useAsyncEffect,內(nèi)部的 useEffect 返回函數(shù)只返回了如下:

return () => {
  // 當(dāng)前 effect 已經(jīng)被清理
  cancelled = true;
};

這說(shuō)明,你通過(guò) useAsyncEffect 沒(méi)有 useEffect 返回函數(shù)中執(zhí)行清除副作用的功能。

你可能會(huì)覺(jué)得,我們將 effect(useAsyncEffect 的回調(diào)函數(shù))的結(jié)果,放入到 useAsyncEffect 中不就可以了?

實(shí)現(xiàn)最終類(lèi)似如下:

function useAsyncEffect(effect: () => Promise<void | (() => void)>, dependencies?: any[]) {
  return useEffect(() => {
    const cleanupPromise = effect()
    return () => { cleanupPromise.then(cleanup => cleanup && cleanup()) }
  }, dependencies)
}

這種做法在這個(gè) issue 中有討論,上面有個(gè)大神的說(shuō)法我表示很贊同:

他認(rèn)為這種延遲清除機(jī)制是不對(duì)的,應(yīng)該是一種取消機(jī)制。否則,在鉤子已經(jīng)被取消之后,回調(diào)函數(shù)仍然有機(jī)會(huì)對(duì)外部狀態(tài)產(chǎn)生影響。他的實(shí)現(xiàn)和例子我也貼一下,跟 useAsyncEffect 其實(shí)思路是一樣的,如下:

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

function useAsyncEffect(effect: (isCanceled: () => boolean) => Promise<void>, dependencies?: any[]) {
  return useEffect(() => {
    let canceled = false;
    effect(() => canceled);
    return () => { canceled = true; }
  }, dependencies)
}

Demo:

useAsyncEffect(async (isCanceled) => {
  const result = await doSomeAsyncStuff(stuffId);
  if (!isCanceled()) {
    // TODO: Still OK to do some effect, useEffect hasn't been canceled yet.
  }
}, [stuffId]);

其實(shí)歸根結(jié)底,我們的清除機(jī)制不應(yīng)該依賴(lài)于異步函數(shù),否則很容易出現(xiàn)難以定位的 bug。

總結(jié)與思考

由于 useEffect 是在函數(shù)式組件中承擔(dān)執(zhí)行副作用操作的職責(zé),它的返回值的執(zhí)行操作應(yīng)該是可以預(yù)期的,而不能是一個(gè)異步函數(shù),所以不支持回調(diào)函數(shù) async...await 的寫(xiě)法。

我們可以將 async...await 的邏輯封裝在 useEffect 回調(diào)函數(shù)的內(nèi)部,這就是 ahooks useAsyncEffect 的實(shí)現(xiàn)思路,而且它的范圍更加廣,它支持的是所有的異步函數(shù),包括 generator function。

參考    React useEffect 不支持 async function 

以上就是useEffect支持async及await使用方式的詳細(xì)內(nèi)容,更多關(guān)于useEffect支持async及await的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • React.js?Gird?布局編寫(xiě)鍵盤(pán)組件

    React.js?Gird?布局編寫(xiě)鍵盤(pán)組件

    這篇文章主要介紹了React.js?Gird?布局編寫(xiě)鍵盤(pán)組件,Grid?布局則是將容器劃分成"行"和"列",產(chǎn)生單元格,然后指定"項(xiàng)目所在"的單元格,可以看作是二維布局
    2022-09-09
  • react-redux的connect與React.forwardRef結(jié)合ref失效的解決

    react-redux的connect與React.forwardRef結(jié)合ref失效的解決

    這篇文章主要介紹了react-redux的connect與React.forwardRef結(jié)合ref失效的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • react echarts刷新不顯示問(wèn)題的解決方法

    react echarts刷新不顯示問(wèn)題的解決方法

    最近在寫(xiě)項(xiàng)目的時(shí)候遇到了一個(gè)問(wèn)題,當(dāng)編輯完代碼后echarts圖正常展示 , 可再次刷新頁(yè)面 , echarts會(huì)消失,所以本文給大家介紹了react echarts刷新不顯示問(wèn)題原因和解決方法,需要的朋友可以參考下
    2024-02-02
  • React+Spring實(shí)現(xiàn)跨域問(wèn)題的完美解決方法

    React+Spring實(shí)現(xiàn)跨域問(wèn)題的完美解決方法

    這篇文章主要介紹了React+Spring實(shí)現(xiàn)跨域問(wèn)題的完美解決方法,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-08-08
  • React Native 圖片查看組件的方法

    React Native 圖片查看組件的方法

    這篇文章主要介紹了React Native 圖片查看組件的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-03-03
  • 淺談React Event實(shí)現(xiàn)原理

    淺談React Event實(shí)現(xiàn)原理

    這篇文章主要介紹了淺談React Event實(shí)現(xiàn)原理,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-09-09
  • VSCode配置react開(kāi)發(fā)環(huán)境的步驟

    VSCode配置react開(kāi)發(fā)環(huán)境的步驟

    本篇文章主要介紹了VSCode配置react開(kāi)發(fā)環(huán)境的步驟,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-12-12
  • React hooks使用方法全面匯總

    React hooks使用方法全面匯總

    這篇文章主要介紹了react hooks實(shí)現(xiàn)原理,文中給大家介紹了useState dispatch函數(shù)如何與其使用的Function Component進(jìn)行綁定,實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-10-10
  • 每天學(xué)習(xí)一個(gè)hooks?useMount

    每天學(xué)習(xí)一個(gè)hooks?useMount

    這篇文章主要為大家介紹了每天學(xué)習(xí)一個(gè)hooks?useMount,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • React 添加引用路徑時(shí)如何使用@符號(hào)作為src文件

    React 添加引用路徑時(shí)如何使用@符號(hào)作為src文件

    這篇文章主要介紹了React 添加引用路徑時(shí)如何使用@符號(hào)作為src文件,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-06-06

最新評(píng)論