useEffect exhaustive-deps 警告:这试图避免哪些可能的问题?

Posted

技术标签:

【中文标题】useEffect exhaustive-deps 警告:这试图避免哪些可能的问题?【英文标题】:useEffect exhaustive-deps warning: what possible issues is this trying to avoid? 【发布时间】:2021-07-29 01:38:38 【问题描述】:

我意识到有很多关于 React 的 useEffect 钩子的依赖数组的问题,以及可能因缺少依赖项而出现的 eslint 警告。关于此的其他一些很好的讨论:

How to fix missing dependency warning when using useEffect React Hook React useEffect Missing Dependency React useEffect missing dependecy? React Hook useEffect has a missing dependency with useEffect

虽然这些警告的原因和解决方案非常清楚,但我很难理解的一件事是为什么。首先,快速总结一下,我的理解是useEffect作为三个通用目的:

如果省略其依赖数组,则它的行为类似于 componentDidMount 和 componentDidUpdate:它在组件第一次渲染时运行,并且在所有后续渲染时运行。 如果它的依赖数组是空的,它就像componentDidMount:它可以用来运行首次初始化代码(例如从服务器获取初始数据等)。 否则,您可以在其依赖数组中包含您希望它“监视”的任何变量;当这些变量发生变化时,它会像 componentDidMount 一样,然后像 componentDidUpdate 一样。 (为了完整性:它的返回值也可以用来实现 componentWillUnmount 行为,但这超出了本问题的范围)。

我知道如果 useEffect 引用了在 useEffect 之外声明的任何函数(或其他变量),eslint 会抱怨。根据上述链接,有多种方法可以解决这些警告:将函数定义移动到 useEffect 内(如果 useEffect 之外没有任何东西需要调用它);将函数添加到依赖数组并使用 useCallback 对其进行记忆;使用// eslint-disable-next-line// eslint-disable-line react-hooks/exhaustive-deps 禁用警告;等等这些都是有道理的。我很难理解的是为什么它甚至抱怨这个。

所以,我的具体问题:

    实际上,我无法理解您为什么曾经想要在依赖数组中引用本地函数。例如,如果你有useEffect(() => checkCurrentUser() , []),并且 checkCurrentUser 需要在 useEffect 之外定义,因为它在其他地方被调用,checkCurrentUser 将在每个组件渲染上重新定义(这就是为什么如果我们把它放在数组中,我们应该用/ 使用回调)。但对我来说,为什么要在依赖数组中使用它是没有逻辑意义的。那么为什么这甚至是一个警告呢?这个警告实际上有助于防止什么?在我看到警告的所有时间里,在每种情况下,应用程序的行为都完全符合我的预期/预期。

    如果 useEffect 的主要目的之一是像 componentDidMount 一样“运行一次”,而实现该行为的方法是显式放置一个空数组,那么如果指定一个空数组为什么会麻烦呢?我可以理解为什么如果您有一个包含一些引用但不包含其他引用的依赖项数组时发出警告可能是有意义的——就像在“哎呀,你忘记了一些”中一样——但空数组是一个特定的、定义明确的用法。对我来说,告诉您“空数组是一个问题”似乎没有任何意义,因为这是实现 componentDidMount 类型初始化的唯一方法。这感觉就像只是警告你“不要使用 componentDidMount()”。如果这应该是 useEffect 的 3 个主要用途之一,为什么它会抱怨空数组?

再次,我确实了解出现警告的情况以及解决方法。我只是很难理解即使拥有它的好处,(1)在函数的情况下(我们明确知道每次渲染都会改变),以及(2)在空数组的情况下(这是一个特定的用法)。

【问题讨论】:

【参考方案1】:

(1) 在函数的情况下(我们明确知道会改变 每次渲染)

要求将函数放在依赖项中的原因 seems to be 与他们要求您将任何其他值放在依赖项中的原因相同: 可能发生的情况是,您正在使用的函数可能本身引用了组件范围内的某些值,这可能会变得陈旧。

(2)在空数组的情况下(这是一个特定的用法)。

在这种情况下,我将参考 Dan Abramov 从this 评论中引用的答案:

我认为类生命周期方法的最大问题是 componentDidMount 是我们倾向于认为它是一个孤立的 方法,但实际上它是流程的一部分。如果您在 componentDidMount 你很可能需要处理它 componentDidUpdate 也是如此,否则您的组件可能会出错。这是 规则试图修复什么,您需要随着时间的推移处理值......

您可以在该帖子中找到有关他们为什么这样做的更多信息。

【讨论】:

这是正确的,至于 OP 关于希望效果只运行一次但必须在依赖项数组中引用函数的问题:如果您的函数不更改引用,它真的只会运行一次,这在逻辑上是一致的。正如作者所指出的,useCallback 是他们所引用场景的正确解决方案。 回复:第一个答案,哦,有道理!!你认为这样说“作为一项规则,只要我们有在 useEffect() 和其他地方都调用的函数,将它们包装在 useCallback 中并将它们放入 useEffect 的 deps 数组中,它的行为与数组相同,这是否公平?是空的吗?” 在第二种情况下,我想特定的用法是可能的——但是,它感觉就像一个非常罕见/极端的情况,linter 可以明确地寻找(即它可以寻找 setInterval)。如果您专门留出 setInterval,对空数组发出警告对您来说仍然有意义吗? @CoryHarper 抱歉,不确定您的意思。 @Metal450 你所说的useCallbackuseEffect 是真的,但前提是useCallback 的依赖关系不改变。

以上是关于useEffect exhaustive-deps 警告:这试图避免哪些可能的问题?的主要内容,如果未能解决你的问题,请参考以下文章

ESLint 希望 setSate 作为 useEffect 的依赖项,但这会导致无限循环(react-hooks/exhaustive-deps)

了解 react-hooks/exhaustive-deps useEffect 和调度事件

React Hook useEffect 缺少依赖项:'location.state'。要么包含它,要么移除依赖数组 react-hooks/exhaustive-deps

UseEffect - React Hook useEffect 缺少依赖项:

未找到规则“re​​act-hooks/exhaustive-deps”的定义

如何在自定义挂钩上使用 useCallback?