<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>

          在React使用中避免競爭條件和內(nèi)存泄漏

          共 3352字,需瀏覽 7分鐘

           ·

          2021-02-24 20:15

          關(guān)注公眾號?前端人,回復“加群

          添加無廣告優(yōu)質(zhì)學習群

          文章來源:Dev

          文章地址:dev.to/saranshk/avoiding-race-conditions-and-memory-leaks-in-react-useeffect-3mme

          讓我們學習如何處理“Can’t perform a React state update on an unmounted component”警告

          讓我們看一下從API請求獲取數(shù)據(jù)的實現(xiàn),并查看此組件中是否有發(fā)生競爭情況的可能性:

          import?React,?{?useEffect}?from?'react';
          export?default?function?UseEffectWithRaceCondition()?{
          ??const?[todo,?setTodo]?=?useState(null);
          ??useEffect(()?=>?{
          ????const?fetchData?=?async?()?=>?{
          ??????const?response?=?await?fetch('https://jsonplaceholder.typicode.com/todos/1');
          ??????const?newData?=?await?response.json();
          ??????setTodo(newData);
          ????};
          ????fetchData();
          ??},?[]);
          ??if?(data)?{
          ????return?<div>{data.title}div>;
          ??}?else?{
          ????return?null;
          ??}
          }

          我們已經(jīng)指定了一個空數(shù)組作為對useEffect React hook的依賴。因此,我們確保獲取請求僅發(fā)生一次。但是此組件仍然容易出現(xiàn)爭用情況和內(nèi)存泄漏。如何?

          如果API服務(wù)器花了一些時間來響應并且在接收到響應之前已卸載組件,則會發(fā)生內(nèi)存泄漏。盡管已卸載該組件,但仍會在完成時收到對請求的響應。然后將解析響應并調(diào)用setTodo。React會發(fā)出警告:

          無法在已卸載的組件上執(zhí)行React狀態(tài)更新。這是空操作,但它表明應用程序中發(fā)生內(nèi)存泄漏。要修復,請取消使用useEffect清理功能中的所有訂閱和異步任務(wù)。

          消息非常簡單。

          相同問題的另一個潛在情況可能是待辦事項列表ID作為道具被傳遞。

          import?React,?{?useEffect}?from?'react';
          export?default?function?UseEffectWithRaceCondition(?{id}?)?{
          ??const?[todo,?setTodo]?=?useState(null);
          ??useEffect(()?=>?{
          ????const?fetchData?=?async?()?=>?{
          ??????const?response?=?await?fetch(`https://jsonplaceholder.typicode.com/todos/${id}`);
          ??????const?newData?=?await?response.json();
          ??????setTodo(newData);
          ????};
          ????fetchData();
          ??},?[id]);
          ??if?(data)?{
          ????return?<div>{data.title}div>;
          ??}?else?{
          ????return?null;
          ??}
          }

          如果鉤子在請求完成之前收到了另一個ID,而第二個請求在第一個請求之前完成了,那么我們將在組件中看到第一個請求的數(shù)據(jù)。

          競態(tài)條件問題的潛在解決方案 有兩種方法可以解決此問題。兩種方法都利用useEffect提供的清除功能。

          我們可以使用布爾標志來確保組件已安裝。這樣,我們僅在標志為true時更新狀態(tài)。而且,如果我們在一個組件內(nèi)發(fā)出多個請求,我們將始終顯示最后一個的數(shù)據(jù)。

          每當卸載組件時,我們都可以使用AbortController取消先前的請求。IE中不支持AbortController。因此,如果要使用這種方法,我們需要考慮一下。

          useEffect清理與布爾標志

          useEffect(()?=>?{
          ??let?isComponentMounted?=?true;
          ????const?fetchData?=?async?()?=>?{
          ??????const?response?=?await?fetch('https://jsonplaceholder.typicode.com/todos/1');
          ??????const?newData?=?await?response.json();
          ??????if(isComponentMounted)?{
          ????????setTodo(newData);
          ??????}
          ????};
          ????fetchData();
          ????return?()?=>?{
          ??????isComponentMounted?=?false;
          ????}
          ??},?[]);

          此修補程序依賴useEffect的清除功能的工作方式。如果一個組件渲染多次,則在執(zhí)行下一個效果之前,將清除上一個效果。

          由于這種工作方式,由于ID發(fā)生了更改,因此對于我們的其他多個請求示例也可以正常工作。從某種意義上說,我們?nèi)匀惶幱诟偁帬顟B(tài),即在后臺會有多個請求在運行。但是,只有上一個請求的結(jié)果才會顯示在UI上。

          使用AbortController進行useEffect清理

          盡管以前的方法可行,但這并不是處理比賽條件的最佳方法。這些請求在后臺進行。在后臺使用過時的請求是不必要地消耗了用戶的帶寬。瀏覽器也限制了并發(fā)請求的最大數(shù)量(最大6-8)。

          從上一篇有關(guān)如何取消HTTP提取請求的文章中,我們了解到已添加到DOM標準的AbortController API。我們可以利用它完全中止我們的請求。

          useEffect(()?=>?{
          ??let?abortController?=?new?AbortController();
          ????const?fetchData?=?async?()?=>?{
          ??????try?{
          ????????const?response?=?await?fetch('https://jsonplaceholder.typicode.com/todos/1',?{
          ????????????signal:?abortController.signal,
          ??????????});
          ??????const?newData?=?await?response.json();
          ????????setTodo(newData);
          ??????}
          ??????catch(error)?{
          ?????????if?(error.name?===?'AbortError')?{
          ??????????//?Handling?error?thrown?by?aborting?request
          ????????}
          ??????}
          ????};
          ????fetchData();
          ????return?()?=>?{
          ??????abortController.abort();
          ????}
          ??},?[]);

          由于中止請求會引發(fā)錯誤,因此我們需要顯式處理它。

          而且該解決方案的工作方式與上一個類似。在重新渲染的情況下,執(zhí)行下一個效果之前將執(zhí)行清除功能。不同之處在于,由于我們使用的是AbortController,瀏覽器也會取消請求。

          這是我們在使用React的useEffect鉤子發(fā)出API請求時避免競爭條件的兩種方法。如果要使用允許取消請求的某些第三方庫作為一項功能,則可以使用Axios或React查詢來提供許多其他功能。

          • 回復資料包領(lǐng)取我整理的進階資料包
          • 回復加群,加入前端進階群
          • console.log("點贊===看===你我都快樂"
          • Bug離我更遠了,快樂離我更近了

          瀏覽 186
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                  污污污污污www网站免费观看 | 黄色视频在线试看 | 99精品一区二区三区 | 久久一区二区三区四区六区 | 亚洲无码AV在线亚洲有码AV在线精品 |