useEffect 依赖数组和 ESLint exhaustive-deps 规则

useEffect dependency array and ESLint exhaustive-deps rule

我有一个看起来像这样的组件:

const MyComponent = props => {
  const { checked, onChange, id } = props;
  const [isChecked, setChecked] = useState(false);

  useEffect(() => {
    onChange && onChange({ isChecked: !!checked, id });
    setChecked(checked);
  }, [checked]);

  const childProps = {
    id,
    isChecked
  };

  return <ChildComponent {...childProps} />;
};

详尽的 lint 规则不满意:

React Hook useEffect has missing dependencies: id and onChange. Either include them or remove the dependency array. (react-hooks/exhaustive-deps)eslint

我知道 idonChange 不会改变,因此将它们添加到依赖项数组似乎没有必要。但规则不是警告,而是明确的指示。

是否是ESLint规则:

1) 在这种情况下过于谨慎而且有点愚蠢,可以忽略吗?

2) 突出最佳实践 - 即最大限度地减少将来可能发生的意外错误,例如,父组件的更改意味着 id 在将来的某个时候更改?

3) 当前代码显示 actual/possible 问题?

实际上规则非常简单:要么传递一个包含所有依赖项的数组,要么什么都不传递。所以我想这个规则并不愚蠢,它只是不知道依赖关系是否会改变。所以是的,如果您要传递一组依赖项,它应该包含所有依赖项,包括那些您知道不会改变的事实。像这样的东西会发出警告:

useEffect(() => dispatch({ someAction }), [])

要解决此问题,您应该将 dispatch 作为依赖项传递,即使它永远不会更改:

useEffect(() => dispatch({ someAction }), [dispatch])

不要禁用详尽的 deps 规则,如前所述 here


2021 年 5 月 4 日更新

地址. This is no longer necessary since eslint pull #1950

现在,具有稳定签名的引用类型(例如来自 useStateuseDispatch 的引用类型可以安全地用于效果内部而不会触发 exhaustive-deps,即使来自 props

看待它的方式是每个渲染都有自己的效果。如果效果与一组特定的值相同,那么我们可以在 dependencies 数组中告诉 React 这些值。理想情况下,具有相同状态和道具的组件在渲染和效果完成后将始终具有相同的输出(渲染组件 + 效果)。这就是它对错误更有弹性的原因。

规则的要点是,如果 deps 确实发生变化,效果应该再次 运行,因为它现在是不同的效果。

这 3 个链接也提供了更多关于此的见解: