【问题标题】:Missing dependency linting error on React hookReact 挂钩上缺少依赖项 linting 错误
【发布时间】:2020-08-17 01:56:09
【问题描述】:

我在 React 函数组件中使用 useEffect,如下所示:

useEffect(() => {
  const handleRouteChangeComplete = () => {
    window.scrollTo(0, 0);
    userInterface.dispatch(closeNavigation());
  };

  Router.events.on('routeChangeComplete', handleRouteChangeComplete);
}, []);

useEffect 上的第二个(数组)选项给了我以下 linting 错误:

React Hook useEffect has a missing dependency: 'userInterface'. Either include it or remove the dependency array. eslint(react-hooks/exhaustive-deps)

我认为 linting 错误中的任何一个选项都不正确。

  • 我只想初始化一次事件监听器。
  • 如果我删除数组选项,useEffect 将表现得像 componentDidUpdate 并且可以多次执行代码
  • 如果我添加 userInterface 作为对 useEffect 的依赖项,如果上下文更新,它也会多次执行代码

我是在这里遗漏了什么还是 linting 迫使我写出不正确的逻辑?

我会在这个实例中禁用规则,但我的应用中有 4 个其他实例出现类似错误。

【问题讨论】:

  • 你打算用另一个实例替换当前的userInterface 吗?如果您不打算替换它,则将其用作依赖项不会在第一次之后调用useEffect
  • @OriDrori userInterface.state 可能会改变,但 userInterface.dispatch 不应该。但是按照我当前代码的编写方式,如果 userInterface.state 发生更改,将 userInterface 作为依赖项添加到 useEffect 将导致代码再次执行。

标签: reactjs react-hooks eslint eslint-config-airbnb


【解决方案1】:

eslint 错误是有原因的,这是为了防止由于陈旧值而难以注意到的错误。本质上,lint 错误只是告诉您,您的 userInterface 变量将在效果中过时。

忽略该错误不一定是个好主意,因为如果您添加更多依赖项,您可能不会意识到为什么事情没有像您预期的那样更新。

关于同一件事的另一篇文章:

useEffect dependency array and ESLint exhaustive-deps rule

https://github.com/facebook/create-react-app/issues/6880

您应该记住的一件重要事情是确保清理您的操作,无论它是否仅在装载时执行,因为有时如果您不清理它,效果可能会超出组件的生命周期.

你有几个不同的选项来解决这个问题,如果调度是稳定的(基于名称,通常是稳定的),那么你可以从 userInterface 变量中提取调度,然后将它添加到依赖数组中。

const { dispatch } = userInterface;

useEffect(() => {
  const handleRouteChangeComplete = () => {
    window.scrollTo(0, 0);
    dispatch(closeNavigation());
  };

  Router.events.on('routeChangeComplete', handleRouteChangeComplete);
  () => {
    Router.events.off('routeChangeComplete', handleRouteChangeComplete);
  };
}, [dispatch]);

如果提取调度值不是一个选项,那么您可以使用 ref 来确保以稳定的方式保持最新版本的 userInterface。有时这是一项足够常见的任务,您可能希望将逻辑提取到自定义挂钩以获取值的引用。

const userInterfaceRef = useRef(userInterface);
useEffect(() => {
  userInterfaceRef.current = userInterface;
}, [userInterface]);

useEffect(() => {
  const handleRouteChangeComplete = () => {
    window.scrollTo(0, 0);
    userInterfaceRef.current.dispatch(closeNavigation());
  };

  Router.events.on('routeChangeComplete', handleRouteChangeComplete);
  () => {
    Router.events.off('routeChangeComplete', handleRouteChangeComplete);
  };
}, []);

这里看似额外的 useEffect 的原因是因为除非你确定 userInterface 永远不会改变,否则你需要保持它是最新的,否则 userInterfaceRef 将是陈旧的。我之所以使用 userInterface 的 ref 而不是 dispatch 函数,是因为这样您就可以在效果中使用 userInterface 的其他属性而不会出现任何问题。

如果您需要在效果中具有不希望重新启动效果的依赖项,请使用我描述的 ref 选项来确保您拥有最新的值,而无需在每次更改时重新运行效果。

如果您在效果中强制添加 on 处理程序,则应确保将其清理干净。这是一个好习惯。

【讨论】:

  • 您好,谢谢您的回复!不过有几个后续问题。在您的 ref 示例中,由于 dispatch 永远不应该改变,第一个 useEffect 是否不需要与 ref 保持同步?其次,是否存在这种 linting 规则,因为有充分的理由声明 useEffect 的所有依赖项,即使您不想在某些代码更改时重新执行代码?此外,我确实对我的componentDidMount 进行了清理,但为了在这个问题中简洁起见,我将其删除。感谢您指出这一点!
  • React 函数式组件是 Facebook 的一个笨拙的实现。他们制造的问题多于解决的问题。
猜你喜欢
  • 1970-01-01
  • 2020-06-12
  • 1970-01-01
  • 2020-09-03
  • 2021-08-19
  • 2014-12-11
  • 2019-10-24
  • 1970-01-01
相关资源
最近更新 更多