如何修复 “React Hook useEffect Has a Missing Dependency” 错误

如何修复 "React Hook useEffect Has a Missing Dependency" 错误

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;

在上例中,您有一个使用 useStateuseEffect 挂钩的功能组件。每当 count 状态变量的值发生变化时, useEffect 钩子就会记录一条信息。

但请注意,count 变量并没有列在 useEffect 钩子的第二个参数数组(依赖数组)中。这将触发 “React Hook useEffect has a missing dependency” 错误。

React 钩子 useEffect 有一条缺少依赖关系的错误信息

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 钩子来解决这个问题。

现在轮到你了: 您遇到过这个问题吗?你是如何解决的?您还使用过本文未涉及的其他方法吗?请在评论中告诉我们!

评论留言