React useEffect
鉤子自 16.8 版推出以來,已成為 React 庫中的一項流行功能。它使開發人員能夠在功能元件中執行副作用,如獲取資料、更新 DOM 和訂閱事件。
不過, useEffect
鉤子的使用有時會很棘手。開發人員遇到的一個常見錯誤是 “React Hook useEffect has a missing dependency. Either include it or remove the dependency array” 的錯誤。
在本文中,我們將討論導致該錯誤的原因,並提供如何修復該錯誤的各種解決方案。
什麼原因導致 “React Hook useEffect Has a Missing Dependency” 錯誤?
當 useEffect
鉤子的依賴關係陣列不完整或丟失時,就會出現 “React Hook useEffect has a missing dependency”(React 鉤子使用效果缺少依賴關係)錯誤。
依賴關係陣列是 useEffect
鉤子中的第二個引數,用於指定效果所依賴的變數。這意味著當依賴關係陣列中指定的變數值發生變化時,將重新執行效果。
如果效果所依賴的變數未包含在依賴關係陣列中,那麼當變數值發生變化時,效果可能不會被重新執行。這可能會導致應用程式出現意外行為和錯誤。
此錯誤不是 React 錯誤,而是 ESLint 錯誤。ESLint 專門為 React 提供了一個外掛,其中包含一套規則,旨在幫助開發人員編寫更好的 React 程式碼。其中一個規則是 "react-hooks/exhaustive-deps"
規則,它可以檢測 “React Hook useEffect has a missing dependency” 錯誤。
舉例來說,我們來看一個具有計數狀態的功能元件。每當計數狀態發生變化時,該元件也要向控制檯記錄一條包含 count
值的訊息:
import { useState, useEffect } from 'react'; const App = () => { const [count, setCount] = useState(0); useEffect(() => { console.log(`You clicked ${count} times`); }, []); return ( <div> <h1>Hello World</h1> <p>Count: {count}</p> <button onClick={() => setCount(count + 1)}>Increment</button> </div> ); }; export default App;
在上例中,您有一個使用 useState
和 useEffect
掛鉤的功能元件。每當 count
狀態變數的值發生變化時, useEffect
鉤子就會記錄一條資訊。
但請注意,count
變數並沒有列在 useEffect
鉤子的第二個引數陣列(依賴陣列)中。這將觸發 “React Hook useEffect has a missing dependency” 錯誤。
React 鉤子 useEffect 有一條缺少依賴關係的錯誤資訊
修復 “React Hook useEffect Has a Missing Dependency” 錯誤的 3 種方法
根據您希望使用的方法,可以用不同的方式來修復這個錯誤。以下是各種方法。
- 包含所有缺失的依賴關係
- 在處理物件和函式時使用 memoization 鉤子
- 禁用 ESLint 規則
1. 將缺失的依賴關係新增到 useEffect 依賴關係陣列中
解決這一錯誤的直接方法是將 useEffect
鉤子中使用的所有依賴關係都加入依賴關係陣列。那麼您可能會問,我如何知道依賴關係呢?
要識別缺失的依賴關係,您需要檢視 useEffect
鉤子中使用的變數或值。如果這些變數或值會隨著時間的推移而發生變化,那麼它們就應該包含在依賴關係陣列中。
例如,在前面提供的程式碼片段中, useEffect
鉤子內部使用了 count
變數,但它並沒有包含在依賴關係陣列中。這意味著如果 count
變數發生變化,useEffect
鉤子將不會被重新執行,元件可能會出現過時資料或其他問題。
要解決這個錯誤,我們可以將 count
變數新增到依賴關係陣列中,就像下面這樣:
import { useState, useEffect } from 'react'; const App = () => { const [count, setCount] = useState(0); useEffect(() => { console.log(`You clicked ${count} times`); }, [count]); return ( <div> <h1>Hello World</h1> <p>Count: {count}</p> <button onClick={() => setCount(count + 1)}>Increment</button> </div> ); }; export default App;
通過將 count
變數新增到依賴關係陣列,我們可以告訴 React,只要 count 變數發生變化,就會重新執行 useEffect
鉤子。
這將確保元件始終擁有最新資料,並避免出現 “React Hook useEffect has a missing dependency” 的錯誤。
如果您有多個依賴項,請將它們新增到依賴項陣列中,並用逗號將它們分開:
import { useState, useEffect } from 'react'; const App = () => { const [firstName, setFirstName] = useState(''); const [lastName, setLastName] = useState(''); const [fullName, setFullName] = useState(''); useEffect(() => { setFullName(`${firstName} ${lastName}`); }, [firstName, lastName]); const handleFirstNameChange = (event) => { setFirstName(event.target.value); }; const handleLastNameChange = (event) => { setLastName(event.target.value); }; return ( <div> <label> First Name: <input type="text" value={firstName} onChange={handleFirstNameChange} /> </label> <label> Last Name: <input type="text" value={lastName} onChange={handleLastNameChange} /> </label> <p>Full Name: {fullName}</p> </div> ); }; export default App;
2. 處理物件和函式
在使用物件和陣列時,僅將它們新增到依賴陣列中是不夠的,還需要將它們 memoize 或移動到 useEffect
鉤子中或元件外部,以避免不必要的重新呈現。
這是因為在 JavaScript 中,物件和陣列是通過引用進行比較的,每次都指向記憶體中的不同位置,因此每次呈現時其值都會改變,從而導致無限的重新呈現迴圈。
下面是一個導致錯誤的示例:
import { useState, useEffect } from 'react'; const App = () => { const [user, setUser] = useState({}); // 👇️this will change on every render let newUser = { name: 'Jane', age: 28 }; useEffect(() => { setUser(newUser); }, [newUser]); return ( <div> <h1>Hello World</h1> </div> ); }; export default App;
您可以通過將物件移入 useEffect
鉤子或將其移出元件來解決這個錯誤:
import { useState, useEffect } from 'react'; const App = () => { const [user, setUser] = useState({}); useEffect(() => { let newUser = { name: 'Jane', age: 28 }; setUser(newUser); }, []); return ( <div> <h1>Hello World</h1> </div> ); }; export default App;
解決這一問題的更好方法是使用備忘錄化鉤子,如對物件使用 useMemo
,對函式使用 useCallback
。這將有助於在元件和依賴關係陣列中保留物件或函式。
注:memoization 鉤子是一組鉤子,可讓您快取昂貴的計算結果,避免不必要的重新計算。
當您使用 useMemo
鉤子對物件進行記憶化處理時,您的程式碼就會變成這樣:
import { useState, useEffect, useMemo } from 'react'; const App = () => { const [user, setUser] = useState({}); const newUser = useMemo(() => { return { name: 'John', age: 30 }; }, []); useEffect(() => { setUser(newUser); }, [newUser]); return ( <div> <h1>Hello World</h1> </div> ); }; export default App;
同樣,在使用函式時,可以使用 useCallback
鉤子。
3. 禁用 ESLint 規則
“React Hook useEffect has a missing dependency” 錯誤是一個 ESLint 警告錯誤,這意味著我們可以禁用該規則,這樣它就不會丟擲該錯誤。並不建議在所有情況下都採用這種方法,但如果您確定缺少的依賴關係不是一個問題,這種方法可以快速解決問題。
可以在依賴關係陣列行前新增以下注釋。
// eslint-disable-next-line react-hooks/exhaustive-deps
下面就是一個例子:
useEffect(() => { console.log(`You clicked ${count} times`); // eslint-disable-next-line react-hooks/exhaustive-deps }, []);
需要注意的是,如果不小心禁用 ESLint 規則,將來可能會導致其他問題。請確保在禁用規則前徹底瞭解其後果,並儘可能考慮其他解決方案。
小結
“React Hook useEffect has a missing dependency” 錯誤是 React 開發人員在使用 useEffect 掛鉤時面臨的常見問題。
在修復該錯誤時,重要的是要考慮針對特定用例的最佳方法。一般來說,最好避免禁用導致該錯誤的 ESLint 規則,因為這會在將來導致其他問題。相反,可以嘗試在依賴關係陣列中加入缺失的依賴關係,或使用正確的 memoization 鉤子來解決這個問題。
現在輪到你了: 您遇到過這個問題嗎?你是如何解決的?您還使用過本文未涉及的其他方法嗎?請在評論中告訴我們!
評論留言