首頁 > 軟體

如何解決React useEffect勾點帶來的無限迴圈問題

2022-07-07 14:01:23

React的useEffect Hook可以讓使用者處理應用程式的副作用。例如:

  • 從網路獲取資料:應用程式通常在第一次載入時獲取並填充資料。這可以通過useEffect函數實現
  • 操作UI:應用程式應該響應按鈕點選事件(例如,開啟一個選單)
  • 設定或結束計時器:如果某個變數達到預定義值,則內建計時器應自行停止或啟動

儘管useEffect Hook在React生態系統中很常見,但它需要時間來掌握。因此,許多新手開發人員在設定他們的useEffect函數時,會導致無限迴圈問題。在本文中,您將瞭解不同場景下帶來的無限迴圈問題以及如何解決它們。

這是我們今天要學習的內容:

是什麼導致無限迴圈以及如何解決它們:

  • 在依賴項陣列中不傳遞依賴項
  • 使用函數作為依賴項
  • 使用陣列作為依賴項
  • 使用物件作為依賴項
  • 傳遞不正確的依賴項

什麼導致的無限迴圈以及如何解決它們

在依賴項陣列中不傳遞依賴項

如果您的useEffect函數不包含任何依賴項,則會出現一個無限迴圈。

例如,看看下面的程式碼:

function App() {
  const [count, setCount] = useState(0); //初始化值
  useEffect(() => {
    setCount((count) => count + 1); 
  }); //無依賴項
  return (
    <div className="App">
      <p> value of count: {count} </p>
    </div>
  );
}

如果沒有依賴關係,則預設在每個更新週期上觸發useEffect。因此,這裡的應用程式將在每次渲染時執行setCount函數。因此,這會導致一個無限迴圈:

是什麼導致了這個問題?讓我們一步一步來分析這個問題:

  • 在第一次渲染時,React會檢查count的值。在這裡,由於count為0,程式執行useEffect函數
  • 稍後,useEffect呼叫setCount方法並更新count的值
  • 之後,React重新呈現UI以顯示count的更新值
  • 此外,由於useEffect在每個呈現週期中執行,它將重新呼叫setCount函數
  • 由於上述步驟發生在每一個渲染,這導致你的應用程式崩潰

如何解決這個問題

為了緩解這個問題,我們必須使用依賴陣列告訴React只有在特定值更新時才呼叫useEffect。

下一步,像這樣附加一個空白陣列作為依賴項:

useEffect(() => {
  setCount((count) => count + 1);
}, []); //empty array as second argument.

這告訴React在第一次裝載時執行setCount函數。

使用函數作為依賴項

如果你把一個方法傳入你的useEffect依賴陣列,React會丟擲一個錯誤,表明你有一個無限迴圈:

function App() {
  const [count, setCount] = useState(0);

  function logResult() {
    return 2 + 2;
  }
  useEffect(() => {
    setCount((count) => count + 1);
  }, [logResult]); // 函數作為依賴項
  return (
    <div className="App">
      <p> value of count: {count} </p>
    </div>
  );
}

在這段程式碼中,我們將logResult方法傳遞給useEffect陣列。理論上,React只需要在第一次渲染時增加count的值。

是什麼導致了這個問題?

  • 要記住的一件事是,useEffect使用了一個叫做淺比較的概念。它這樣做是為了驗證依賴項是否已經更新
  • 這裡的問題是,在每次呈現期間,React都會重新定義logResult的參照
  • 因此,這將在每個迴圈中重新觸發useEffect函數
  • 因此,React會呼叫setCount勾點,直到應用程式遇到更新深度錯誤。這會給程式帶來錯誤和不穩定性

如何解決這個問題

一個解決方案是使用useCallback勾點。這允許開發人員記住他們的函數,從而確保參照值保持不變。由於這個參考值是穩定的,React不應該無限地重新渲染UI:

const logResult = useCallback(() => {
  return 2 + 2;
}, []); // logResult是快取的
useEffect(()=> {
  setCount((count)=> count+1);
},[logResult]); //沒有無限迴圈錯誤,因為logResult參照保持不變。

結果:

使用陣列作為依賴項

將陣列變數傳遞給依賴項也會執行一個無限迴圈。考慮下面的程式碼範例:

const [count, setCount] = useState(0); //初始值為0。
const myArray = ["one", "two", "three"];

useEffect(() => {
  setCount((count) => count + 1); // 和前面一樣,增加Count的值
}, [myArray]); // 將陣列變數傳遞給依賴項

在這個塊中,我們將myArray變數傳入依賴引數。

是什麼導致了這個問題?

既然myArray的值在整個程式中都沒有改變,為什麼我們的程式碼會多次觸發useEffect ?

  • 在這裡,回想一下React使用淺比較來檢查依賴項的參照是否發生了變化。
  • 由於對myArray的參照在每次渲染時都在變化,useEffect將觸發setCount回撥
  • 因此,由於myArray的參照值不穩定,React將在每個渲染週期中呼叫useEffect。最終,這會導致應用程式崩潰

如何解決這個問題

為了解決這個問題,我們可以使用useRefHook這將返回一個可變物件,確保參照不會改變:

const [count, setCount] = useState(0);
//提取「current」屬性並給它賦值
const { current: myArray } = useRef(["one", "two", "three"]);

useEffect(() => {
  setCount((count) => count + 1);
}, [myArray]); //依賴值是穩定的,所以沒有無限迴圈

將物件作為依賴項傳遞

在useEffect依賴陣列中使用物件也會導致無限迴圈問題。

考慮下面的程式碼:

const [count, setCount] = useState(0);
const person = { name: "Rue", age: 17 }; //建立一個物件
useEffect(() => {
  // 每次增加count的值
  // person的值發生了變化
  setCount((count) => count + 1);
}, [person]); // 依賴項陣列包含一個物件作為引數
return (
  <div className="App">
    <p> Value of {count} </p>
  </div>
);

控制檯的結果表明程式是無限迴圈的:

是什麼導致了這個問題?

  • 和之前一樣,React使用淺比較來檢查person的參考值是否發生了變化
  • 因為person物件的參照值在每次渲染時都會改變,所以React會重新執行useEffect
  • 因此,在每個更新週期中呼叫setCount。這意味著我們現在有了一個無限迴圈

如何解決這個問題

那麼我們如何解決這個問題呢?

這就是usemmo的用武之地。**當依賴關係發生變化時,這個勾點會計算一個記憶的值。**除此之外,因為我們記住了一個變數,這確保了狀態的參照值在每次渲染期間不會改變:

// 使用usemo建立一個物件
const person = useMemo(
  () => ({ name: "Rue", age: 17 }),
  [] //沒有依賴關係,所以值不會改變
);
useEffect(() => {
  setCount((count) => count + 1);
}, [person]);

傳遞不正確的依賴項

如果將錯誤的變數傳遞給useEffect函數,React將丟擲一個錯誤。

下面是一個簡單的例子:

const [count, setCount] = useState(0);

useEffect(() => {
  setCount((count) => count + 1);
}, [count]); //注意,我們將count傳遞給了這個陣列。

return (
  <div className="App">
    <button onClick={() => setCount((count) => count + 1)}>+</button>
    <p> Value of count{count} </p>
  </div>
);

是什麼導致了這個問題?

  • 在上面的程式碼中,我們告訴在useEffect方法中更新count的值
  • 此外,注意我們也將count Hook傳遞給了它的依賴陣列
  • 這意味著每次count值更新時,React都會呼叫useEffect
  • 因此,useEffect勾點呼叫setCount,從而再次更新count
  • 因此,React現在在一個無限迴圈中執行我們的函數

如何解決這個問題

要擺脫無限迴圈,只需像這樣使用一個空的依賴陣列:

const [count, setCount] = useState(0);
// 只有在元件首次掛載時才更新'count'的值
useEffect(() => {
  setCount((count) => count + 1);
}, []);

這將告訴React在第一次渲染時執行useEffect。

結尾

儘管React Hooks是一個簡單的概念,但是在將它們整合到專案中時,仍然需要記住許多規則。這將確保您的應用程式保持穩定,優化,並在生產過程中不丟擲錯誤。

此外,最近釋出的Create React App CLI也會在執行時檢測和報告無限迴圈錯誤。這有助於開發人員在這些問題出現在生產伺服器上之前發現並解決這些問題。

 到此這篇關於如何解決React useEffect勾點帶來的無限迴圈問題的文章就介紹到這了,更多相關React useEffect勾點無限迴圈內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com