我们在 useEffect 中使用的所有变量都在 dependencies 数组中吗?

Are all variables we use in useEffect in dependencies array?

我知道 useEffect 的依赖项是如何工作的。但是在我的场景中,我不应该观察道具值的变化,我将它用作处理流程的条件,但如果我不将它放在依赖项数组中,我将收到 react-hooks/exhaustive-deps 警告。

我的方案是,如果 foo 和 fetchValue 发生变化,我想重新 运行 整个提取。虽然我用bar作为条件来决定调用的是fechValue,但是在我的业务逻辑中,bar的改变不应该重新运行 block.

const Component = ({ foo, bar, fetchValue }) => {
  useEffect = (
    () => {
      if(foo) {
        if (bar) {
          fetchValue();
        }
      }
    },
    [foo, fetchValue] // will get a warning `react-hooks/exhaustive-deps`
  )

  return <div />

}

ESLint 规则用于通过 useEffect 钩子提供安全性。

如果您完全确定该值不是 useEffect 的依赖项,您可以添加注释以忽略 ESLint 规则:Disabling Rules with Inline Comments.

我建议添加 // eslint-disable-next-line 而不是 file-wide eslint-disable

这里是more context about this by Dan Abramov

is there any way I can disable this rule specifically for places where the spread operator is used?

如果你认为你知道自己在做什么,你总是可以// eslint-disable-next-line react-hooks/exhaustive-deps

'useEffect' 中的 if 语句经常出现这样的逻辑。首先,根本不需要添加依赖项,你可以将其留空。

现在您可以做一些事情,要么忽略警告,因为您的代码看起来不错。或者重构你的代码,其中 barfetchValue() 的参数。所以你的代码是:

const Component = ({ foo, bar, fetchValue }) => {
  useEffect = (
    () => {
      if(foo) {
        fetchValue(bar);        
      }
    },
    [foo, fetchValue] 
  )

  return <div />

}

并以 if(baz){ //your code} 开始你的 fetchValue(baz) 声明。

虽然有点麻烦。

您需要问问自己,您希望 foo 或 bar 改变的原因和位置?在组件本身内部? foo and/or bar 不应该是状态然后 foo 和或 bar 作为默认值吗?

const Component = ({ foo, bar, fetchValue }) => {

  const [fooState, setFooState] = useState(foo);
  const [barState, setBarState] = useState(bar);

  useEffect = (
    () => {
      fooState && barState && fetchValue(); 
    //does the same as your code, I just prefer short circuits for these kind of things.
    },
    [fooState, fetchValue()] 
  )

  return <div />

}

你应该把你使用的所有变量放在你的 useEffects 'deps' 数组中的原因是没有这样做会由于陈旧数据而产生奇怪的问题。


例如,给定您的用例,假设您的组件 props 最初是 {foo: false, bar: false }(假设 fetchValue 是某个固定函数),然后它们变为 {foo: true, bar: true}。在这种情况下,您的组件将按预期调用 fetchValue

但是再举个例子,假设你的道具从{foo: false, bar: false}变成了{foo: true, bar: false},然后又变成了{foo: true, bar: true}。在这种情况下,fetchValue 没有触发,尽管道具与上一个示例末尾的道具相同。

也许这本身不是 "wrong",但它确实很奇怪且不直观:理想情况下,您的组件应该根据其 props 一致地运行,并且 props 更改的顺序无关紧要。


所以,是的,您始终可以 eslint-ignore deps 数组以使其不完整,但我个人建议寻找其他解决方案。

如果没有关于用例的更多信息,很难具体说明,但也许可以记住对 fetchValue 的调用,这样如果 foo 没有改变,它就不会做任何事情?或者 foobar 可以组合成一个 prop 一起改变?