繁体   English   中英

带有 useEffect 挂钩的 React Router useNavigate - 正确的使用方法?

[英]React Router useNavigate with a useEffect hook - proper way to use?

我是 React 的新手,正在尝试制作一个加载/问候页面,在显示几秒钟后导航到下一个页面。 在 React Router v6 中,我们有useNavigate()挂钩来允许您控制导航,我正在使用它通过在useEffect()挂钩中设置超时来成功调用导航 function。 但是,编译器抱怨我缺少依赖项。 我只希望它运行一次,而不是每当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

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

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

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

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

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

此警告由 eslint 规则显示。 您可以在How to fix missing dependency warning when using useEffect React Hook

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

不用担心,function 仍将在挂载时运行,并且可以放心, navigate不会改变并导致不需要的第二次setTimeout

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

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

  const navigate = useRef(useNavigate());

  useEffect(() => {
    const timeout = setTimeout(() => navigate.current(props.nextPage), 3000);

    return () => {
      clearTimeout(timeout);
    };
  }, [props.nextPage]);

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

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

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

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

这取决于。

useNavigate()挂钩取决于useLocation().pathname + 其他一些东西

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

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

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

重要的提示:
如果您使用相对路径导航,则需要将naviagate添加为依赖项。
这是因为naviagate使用useLocation().pathname来解析相对路径。
一般来说,我建议尽可能不要使用相对路径。

这里接受的答案说您应该始终将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 警告可以让您更容易忘记添加确实发生变化的变量。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM