如何将缺少的依赖项添加到仅运行一次的 useEffect 挂钩?

Posted

技术标签:

【中文标题】如何将缺少的依赖项添加到仅运行一次的 useEffect 挂钩?【英文标题】:How to add missing dependencies to a useEffect hook that is run only once? 【发布时间】:2021-03-03 07:40:19 【问题描述】:

React Hook useEffect 缺少依赖项:'myDate' 和 'setMyDate'。要么包含它们,要么移除依赖数组。

如何将缺少的依赖项添加到只运行一次的useEffect?以下示例生成上述警告:

const [ myDate, setMyDate ] = useState(0)

const spinner = useRef(null)
useEffect( () => 
    spinner.current = setInterval( () => 
        d = Date.now()
        if (d < myDate)
            setUpdate(d)
    , 997 )
, [])

如果我包含它们,我会创建一个无限循环,因为 setTimeout 会更改依赖项的值:

const spinner = useRef(null)
useEffect( () => 
    spinner.current = setInterval( () => 
        d = Date.now()
        if (d < myDate)
            setMyDate(d)
    , 997 )
, [myDate, setMyDate])

如果我删除依赖数组,useEffect 在每次渲染上运行,并设置无限数量的 setIntervals:

const spinner = useRef(null)
useEffect( () => 
    spinner.current = setInterval( () => 
        d = Date.now()
        if (d < myDate)
            setMyDate(d)
    , 997 )
)

我还尝试完全删除useEffect,认为由于spinneruseRef,它不会在每个组件渲染上重新分配...但没有:

const spinner = useRef(null)
spinner.current = setInterval( () => 
    d = Date.now()
    if (d < myDate)
        setMyDate(d)

也尝试过使用功能更新方法,就像这样,但是 lint 错误仍然存​​在并且代码不起作用:

const spinner = useRef(null)
useEffect( () => 
    spinner.current = setInterval( () => 
        d = Date.now()
        setMyDate(d => 
            if (d < myDate)
                setMyDate(d)
        
    , 997 )
, [setMyDate])

我被卡住了……夹在石头和坚硬的地方之间!如何解决此 lint 警告?

【问题讨论】:

我不知道它是否会起作用,因为有时我有奇怪的无限循环,因为方法没有改变。您可以做的是创建一个设置间隔的方法,并通过将其分配为依赖项来在使用效果中调用此方法。通常它会起作用,因为就像我说的那样,方法不会改变。 你想做什么? @Galupuf 创建一次setInterval,每n秒调用一次钩子更新。 【参考方案1】:

解决方案是从setMyDate 函数本身获取myDate(在我的代码中命名为date),而不是将其作为依赖项传递。

setMyDate 已被记忆,因此不需要作为依赖项传递。

const [myDate, setMyDate] = useState(0);
const spinner = useRef(null);

useEffect(() => 
  spinner.current = setInterval(() => 
    const d = Date.now();

    setMyDate(date => 
      if (d < date) 
        return d;
      
      return date;
    );
  , 997);
, []);

【讨论】:

不错...功能更新方法。就我而言,myDatesetMyDateuseContext 钩子,所以 linter 仍在抱怨 setMyDate @kmiklas 这确实有所作为,您应该在问题中对此进行解释。请编辑您的帖子并添加相关钩子的代码。 瓦伦丁谢谢你。我打算做一个最小的例子。【参考方案2】:

似乎对我有用的是将间隔的逻辑分离到一个没有依赖关系的useCallback() 钩子中。这会记住函数并确保该函数仅在初始组件渲染上构建。

然后,在效果内部调用使用useCallback() 构建的函数,并将其提供给效果依赖项数组。然后,只有在 useCallback() 函数发生变化时才会重建效果——它不会因为它没有依赖关系而重建。

应该从 react-hooks 中删除 linter 警告

import React, useState, useEffect, useRef, useCallback from 'react'

export default function IntervalHook() 

  const [ myDate, setMyDate ] = useState(0)
  const spinner = useRef(0)

  const spinnerFn = useCallback(() => 
    spinner.current = setInterval(() => 
      const d = Date.now()
      setMyDate(d)
    , 997 )
  , [])

  useEffect(() => 
    spinnerFn()     
    return () =>   // this return statement clears the interval when the component unmounts
      if (spinner.current) 
        clearInterval(spinner.current)
        spinner.current = 0
      
    
  , [spinnerFn])

  return (
    <span>myDate</span>
  )

【讨论】:

以上是关于如何将缺少的依赖项添加到仅运行一次的 useEffect 挂钩?的主要内容,如果未能解决你的问题,请参考以下文章

如何绕过 React 的 useEffect() “缺少依赖项”警告?

将 css 样式添加到仅包含子项的列表项

如何将通过 npm 安装的所有依赖项保存到我的 package.json 文件中?

如何将自定义 osgi 包添加为新依赖项?

如何解决“React Hook useEffect 缺少依赖项。包括它或删除依赖项数组”问题?

如何修复 python 缺少的依赖项 - Homebrew