在React钩子上缺少依赖项掉毛错误

时间:2020-05-02 15:23:21

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

我正在像这样的React函数组件中使用useEffect

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

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

useEffect上的第二个(数组)选项为我带来了以下掉毛错误:

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

我认为棉绒错误中的两个选项都不正确。

  • 我只想初始化一次事件监听器。
  • 如果删除数组选项,useEffect的行为将类似于componentDidUpdate,并且可以多次执行代码
  • 如果我将userInterface添加为对useEffect的依赖项,并且在上下文更新的情况下,它还会多次执行代码

我在这里错过了什么吗?还是被迫强迫我写错了逻辑?

我会在此情况下禁用该规则,但我的应用中还有其他4个类似错误的情况。

1 个答案:

答案 0 :(得分:2)

存在eslint错误的原因是为了防止由于过时的值而导致难以发现的错误。本质上,lint错误只是告诉您效果中的userInterface变量将过时。

消除该错误并不一定是一个好主意,因为如果您添加更多的依赖项,您可能会不明白为什么事情没有像您期望的那样更新。

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

useEffect dependency array and ESLint exhaustive-deps rule

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

您应该记住的主要事情是确保清理操作,而不管它是否只是在安装时完成,因为有时,如果不清理,效果可能会超出组件的寿命

您有几种不同的解决方法,如果调度是稳定的(基于名称,通常是稳定的),则可以从userInterface变量中拉出调度,然后将其添加到依赖项数组中。 / p>

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而不是dispatch函数的原因是因为这样您可以在效果内使用userInterface的其他属性而没有任何问题。

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

如果要在效果中强制将on处理程序添加到某些内容中,则应确保将其清理干净。养成好习惯。