日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側工具欄

新聞中心

這里有您想知道的互聯網營銷解決方案
使用React/Hooks時需要注意過時的閉包!

本文已經過原作者 Shadeed 授權翻譯。

我們提供的服務有:做網站、成都網站建設、微信公眾號開發(fā)、網站優(yōu)化、網站認證、東烏珠穆沁ssl等。為近1000家企事業(yè)單位解決了網站和推廣的問題。提供周到的售前咨詢和貼心的售后服務,是有科學管理、有技術的東烏珠穆沁網站制作公司

Hooks 簡化了 React 組件內部狀態(tài)和副作用的管理。此外,可以將重復的邏輯提取到自定義 Hooks 中,以在整個應用程序中重復使用。

Hooks 嚴重依賴于 JS 閉包。這就是為什么 Hooks 如此具有表現力和簡單,但是閉包有時很棘手。

使用 Hooks 時可能遇到的一個問題就是過時的閉包,這可能很難解決。

讓我們從過時的裝飾開始。然后,看看到過時的閉包如何影響 React Hooks,以及如何解決該問題。

1.過時的閉包

工廠函數 createIncrement(incBy) 返回一個increment和log函數的元組。調用時,increment()函數將內部value增加incBy,而log()僅打印一條消息,其中包含有關當前value的信息:

 
 
 
 
  1. function createIncrement(incBy) {
  2.   let value = 0;
  3.   function increment() {
  4.     value += incBy;
  5.     console.log(value);
  6.   }
  7.  const message = `Current value is ${value}`; function log() { console.log(message); }  
  8.   return [increment, log];
  9. }
  10. const [increment, log] = createIncrement(1);
  11. increment(); //  1
  12. increment(); //  2
  13. increment(); //  3
  14. // 不能正確工作!
  15. log();       //  "Current value is 0"

[increment, log] = createIncrement(1)返回一個函數元組:一個函數增加內部值,另一個函數記錄當前值。

然后,increment()的3次調用將 value遞增到3。

最后,log()調用打印消息是 Current value is 0,這有點出乎意料的,因為此時 value 為 3 了。

log()是一個過時的閉包。閉包 log()捕獲了值為 "Current value is 0"的 message變量。

即使 value 變量在調用increment()時被增加多次,message變量也不會更新,并且總是保持一個過時的值 "Current value is 0"。

過時的閉包捕獲具有過時值的變量。

2.修復過時的閉包

修復過時的log()問題需要關閉實際更改的變量:value的閉包。

我們將語句 const message = ...; 移動到 log() 函數內部:

 
 
 
 
  1. function createIncrement(incBy) {
  2.   let value = 0;
  3.   function increment() {
  4.     value += incBy;
  5.     console.log(value);
  6.   }
  7.   function log() {
  8.  const message = `Current value is ${value}`;    console.log(message);
  9.   }
  10.   
  11.   return [increment, log];
  12. }
  13. const [increment, log] = createIncrement(1);
  14. increment(); //  1
  15. increment(); //  2
  16. increment(); //  3
  17. // Works!
  18. log();       // "Current value is 3"

現在,在調用了 3 次 increment() 函數之后,調用 log() 記錄了實際value:"Current value is 3"。

3. Hooks 中的過時閉包

3.1 useEffect()

我們來看一下使用useEffect() 過時閉包的常見情況。

在組件中,useEffect() 中每2秒記錄一次count的值

 
 
 
 
  1. function WatchCount() {
  2.   const [count, setCount] = useState(0);
  3.   useEffect(function() {
  4.     setInterval(function log() {
  5.       console.log(`Count is: ${count}`);
  6.     }, 2000);
  7.   }, []);
  8.   return (
  9.     
     {count}  setCount(count + 1) }> Increase  
  10.   );
  11. }

打開事例(https://codesandbox.io/s/stale-closure-use-effect-broken-2-gyhzk)

并點擊幾次增加按鈕。然后看看控制臺,每2秒出現一次Count is: 0,盡管count狀態(tài)變量實際上已經增加了幾次。

為什么會這樣?

第一次渲染時,狀態(tài)變量count初始化為0。

組件安裝后,useEffect()調用 setInterval(log, 2000)計時器函數,該計時器函數計劃每2秒調用一次log()函數。在這里,閉包log()捕獲到count變量為0。

之后,即使在單擊Increase按鈕時count增加,計時器函數每2秒調用一次的log(),使用count的值仍然是0。log()成為一個過時的閉包。

解決方案是讓useEffect()知道閉包log()依賴于count,并在count改變時正確處理間隔的重置

 
 
 
 
  1. function WatchCount() {
  2.   const [count, setCount] = useState(0);
  3.   useEffect(function() {
  4.     const id = setInterval(function log() {
  5.       console.log(`Count is: ${count}`);
  6.     }, 2000);
  7.     return function() {
  8.       clearInterval(id);
  9.     }
  10.  }, [count]);
  11.   return (
  12.     
  13.  {count}
  14.   setCount(count + 1) }>
  15.  Increase
  16.  
  17.  
  •   );
  • }
  • 正確設置依賴項后,一旦count發(fā)生變化,useEffect()就會更新閉包。

    3.2 useState()

    組件有1個button ,以1秒延遲異步增加計數器。

     
     
     
     
    1. function DelayedCount() {
    2.   const [count, setCount] = useState(0);
    3.   function handleClickAsync() {
    4.     setTimeout(function delay() {
    5.       setCount(count + 1);
    6.     }, 1000);
    7.   }
    8.   return (
    9.     
       {count} Increase async 
    10.   );
    11. }

    現在打開演示(https://codesandbox.io/s/use-state-broken-0q994)。快速單擊2次按鈕。計數器僅更新為1,而不是預期的2。

    每次單擊setTimeout(delay, 1000)將在1秒后執(zhí)行delay()。delay()此時捕獲到的 count 為 0。

    兩個delay()都將狀態(tài)更新為相同的值:setCount(count + 1) = setCount(0 + 1) = setCount(1)。

    這是因為第二次單擊的delay()閉包中已捕獲了過時的count變量為0。

    為了解決這個問題,我們使用函數式方法setCount(count => count + 1)來更新count狀態(tài)

     
     
     
     
    1. function DelayedCount() {
    2.   const [count, setCount] = useState(0);
    3.   function handleClickAsync() {
    4.     setTimeout(function delay() {
    5.  setCount(count => count + 1);    }, 1000);
    6.   }
    7.   function handleClickSync() {
    8.     setCount(count + 1);
    9.   }
    10.   return (
    11.     
    12.  {count}
    13.  Increase async
    14.  Increase sync
    15.  
  •   );
  • }
  • 打開演示(https://codesandbox.io/s/use-state-fixed-zz78r)。再次快速單擊按鈕2次。計數器顯示正確的值2。

    當一個返回基于前一個狀態(tài)的新狀態(tài)的回調函數被提供給狀態(tài)更新函數時,React確保將最新的狀態(tài)值作為該回調函數的參數提供

     
     
     
     
    1. setCount(alwaysActualStateValue => newStateValue);

    這就是為什么在狀態(tài)更新過程中出現的過時裝飾問題可以通過函數這種方式來解決。

    4.總結

    當閉包捕獲過時的變量時,就會發(fā)生過時的閉包問題。

    解決過時閉包的有效方法是正確設置React鉤子的依賴項?;蛘?,在失效狀態(tài)的情況下,使用函數方式更新狀態(tài)。

    ~完,我是小智,我要去刷碗了。

    作者:Shadeed 譯者:前端小智 來源:dmitripavlutin原文:https://dmitripavlutin.com/react-hooks-stale-closures/

     本文轉載自微信公眾號「大遷世界」,可以通過以下二維碼關注。轉載本文請聯系大遷世界公眾號。


    分享文章:使用React/Hooks時需要注意過時的閉包!
    本文地址:http://www.dlmjj.cn/article/dhgepjc.html