You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ReactJs/NextJS登录欢迎页5秒自动跳转 状态更新异常如何解决

问题根因

这是React Hook的经典闭包陷阱问题:你给useEffect传入的依赖数组为空,因此useEffect只会在组件首次挂载时执行一次,内部的setInterval回调捕获的是首次渲染时的变量快照,其中redirectSeconds永远是初始值5,所以每次执行setRedirectSeconds(redirectSeconds - 1)都只会把状态设为4,自然不会继续倒计时。

修复方案

可以通过setState的函数式更新语法拿到最新的状态值,同时补充定时器清理逻辑避免内存泄漏,另外你原来代码外层的setTimeout会让倒计时晚1秒启动,总停留时间变成6秒,如果不需要可以直接去掉。

修复后代码如下:

const Welcome: NextPage = (): ReactElement => {
  const [redirectSeconds, setRedirectSeconds] = useState<number>(5);
  const router = useRouter();
  const query = router.query;

  useEffect(() => {
    if (!query?.redirect) return;
    // 启动倒计时定时器
    const interval = setInterval(() => {
      setRedirectSeconds(prev => {
        // 用函数式更新可以拿到上一次的最新状态,不受闭包影响
        if (prev <= 1) {
          clearInterval(interval);
          router.push(query.redirect.toString());
          return 0;
        }
        return prev - 1;
      });
    }, 1000);
    // 组件卸载时清理定时器,避免内存泄漏
    return () => clearInterval(interval);
  }, [query, router]); // 把用到的外部变量加入依赖数组,符合eslint规则

  return (
    <div>
      Welcome, you have successfully logged in, you will be redirected in.. {redirectSeconds}
    </div>
  );
};

export default Welcome;

补充说明

如果需要保留原来的「先等1秒再开始倒计时」的逻辑,只需要把setInterval再套回原来的setTimeout里即可,注意要同时把setTimeout的返回值也加入清理逻辑:

useEffect(() => {
  if (!query?.redirect) return;
  let interval: NodeJS.Timeout;
  const timer = setTimeout(() => {
    interval = setInterval(() => {
      setRedirectSeconds(prev => {
        if (prev <= 1) {
          clearInterval(interval);
          router.push(query.redirect.toString());
          return 0;
        }
        return prev - 1;
      });
    }, 1000);
  }, 1000);
  // 清理所有定时器
  return () => {
    clearTimeout(timer);
    if (interval) clearInterval(interval);
  };
}, [query, router]);

内容的提问来源于stack exchange,提问作者Denis2310

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 15:27:03