首页 > 解决方案 > 如何将缺少的依赖项添加到仅运行一次的 useEffect 挂钩?

问题描述

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在每个渲染上运行,并设置无限数量的 setInterval:

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

我也尝试useEffect完全删除,认为既然spinner是 a useRef,它不会在每个组件渲染上重新分配......但没有:

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 警告?

标签: reactjsdependenciesreact-hooksuse-effectuse-ref

解决方案


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

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

应该从react-hooks

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>
  )
}

推荐阅读