【问题标题】:React Router useNavigate with a useEffect hook - proper way to use?带有 useEffect 挂钩的 React Router useNavigate - 正确的使用方法?
【发布时间】:2023-02-03 06:48:52
【问题描述】:

我是 React 的新手,正在尝试制作一个加载/问候页面,在显示几秒钟后导航到下一个页面。在 React Router v6 中,我们有 useNavigate() 挂钩来允许您控制导航,我使用它通过在 useEffect() 挂钩中设置超时来成功调用导航功能。但是,编译器抱怨我缺少依赖项。不过,我只希望它运行一次,而不是在 navigate 更改时运行。做这个的最好方式是什么?

谢谢!

import { useEffect } from "react";
import { useNavigate } from "react-router-dom";

function Greeting(props) {
  const navigate = useNavigate();
  useEffect(() => {
    setTimeout(() => navigate(props.nextPage), 3000);
  }, []);

  return (
    <div className="Greeting">
      <div>Hello World!</div>
    </div>
  );
}

export default Greeting;

第 9:6 行:React Hook useEffect 缺少依赖项:'navigate'。包括它或删除依赖数组 react-hooks/exhaustive-deps

【问题讨论】:

    标签: javascript reactjs react-hooks react-router react-router-dom


    【解决方案1】:

    useEffect 挂钩缺少依赖项,即回调中引用的 navigate 函数和 props.nextPage。将它们添加到依赖项数组。如果组件在超时自行到期之前卸载,请不要忘记返回清理函数。

    useEffect(() => {
      const timerId = setTimeout(() => navigate(props.nextPage), 3000);
      return () => clearTimeout(timerId);
    }, [navigate, props.nextPage]);
    

    作为一般规则,您应该遵循 linter 的所有指导。 react-hooks/exhaustive-deps 规则可以帮助您编写更好的代码。不要禁用该行的规则,除非你完全知道你在做什么以及如果/当​​你更新回调逻辑并可能更改依赖项时可能会出现什么未来后果。

    【讨论】:

      【解决方案2】:

      由于navigate实际上是一个依赖项,只需将其添加到依赖项数组(useEffect() 钩子中的第二个参数)

      别担心,这个函数仍然会在 mount 上运行,可以肯定的是 navigate 不会改变并导致不需要的第二个 setTimeout

      为了真正安全,您实际上可以放入代码以确保 setTimeout 只运行一次,但无论如何它都是过大的

      【讨论】:

        【解决方案3】:

        您可以通过添加以下内容来简单地隐藏此警告:

        useEffect(() => {
           setTimeout(() => navigate(props.nextPage), 3000);
          // eslint-disable-next-line
        }, []);
        

        此警告由 eslint 规则显示。您可以在How to fix missing dependency warning when using useEffect React Hook阅读更多相关信息

        【讨论】:

          【解决方案4】:

          根据您希望如何设置项目的结构,您可以使用 useRef 挂钩来消除 useNavigate 挂钩所需的依赖性。或者您可以将其添加到依赖项数组中。这是一个这样做的例子。

            const navigate = useRef(useNavigate());
          
            useEffect(() => {
              const timeout = setTimeout(() => navigate.current(props.nextPage), 3000);
          
              return () => {
                clearTimeout(timeout);
              };
            }, [props.nextPage]);
          

          【讨论】:

            【解决方案5】:

            但是,编译器抱怨我缺少依赖项

            这不是编译器错误,而是 eslint 警告。

            ESLint 不是很聪明,不知道是否应该将某些东西添加为依赖项,因此它默认警告您潜在的问题,然后如果您知道它不适用于您,您可以随意禁用此警告。

            useEffect 中使用它时,是否应该将 navigate 添加到依赖项列表中?

            这取决于。

            useNavigate() 钩子依赖于 useLocation().pathname + a few other things

            所以我们可以把问题改成这样:

            如果路径更改,您的useEffect 挂钩是否应该再次运行?

            像这样重新定义问题应该会使新开发人员的答案更加明显。

            这里接受的答案说您应该始终将 navigate 添加到依赖项列表中,但是如果您不知道 navigate 可以更改,这很容易导致难以调试的问题。

            在大多数情况下,你的组件只会存在于一条路径上,所以你做什么并不重要。

            在这里回答的其他人显然对react-router 没有太多经验,因此他们可能从未遇到过选择产生影响的情况。

            无论如何,这是您的选择:

            • 如果路径更改或 props.nextPage 更改,请重新运行挂钩
            const navigate = useNavigate();
            useEffect(() => {
              const timeout = setTimeout(() => navigate(props.nextPage), 3000);
              return () => clearTimeout(timeout);
            }, [navigate, props.nextPage]);
            
            • 仅当props.nextPage 发生变化时才重新运行挂钩
            const navigate = useNavigate();
            useEffect(() => {
              const timeout = setTimeout(() => navigate(props.nextPage), 3000);
              return () => clearTimeout(timeout);
              // eslint-disable-next-line react-hooks/exhaustive-deps
            }, [props.nextPage]);
            
            • 在任何情况下都不要重新运行挂钩(只运行一次)
            const navigate = useNavigate();
            useEffect(() => {
              setTimeout(() => navigate(props.nextPage), 3000);
              return () => clearTimeout(timeout);
              // eslint-disable-next-line react-hooks/exhaustive-deps
            }, []);
            

            注意useEffect回调:

            • 为了在重新运行useEffect 时重置超时,我添加了一个运行clearTimeout() 的回调。
            • 如果用户决定不等待并打开另一个页面,您还需要取消超时。例如,如果您有一个“下一步”按钮,那么您还需要取消超时。
            • 如果启用了 React strict 模式,也需要此回调。

            尝试制作一个加载/问候页面,在显示几秒钟后导航到下一个页面

            我相当确定您不会在那几秒钟内更改路径或 nextPage 道具,因此在您的情况下,无论您是否添加依赖项都不会产生影响。

            我建议添加变量(即使它们不是必需的)的唯一原因是禁用 eslint 警告可以让您更容易忘记添加确实发生变化的变量。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2020-09-25
              • 2022-12-20
              • 2022-12-10
              • 2020-09-15
              • 2023-01-25
              • 1970-01-01
              • 1970-01-01
              • 2023-02-19
              相关资源
              最近更新 更多