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

React使用react-idle-timer实现弹窗后60秒无操作跳转页面

问题排查

你的现有代码无法实现「弹窗弹出后60秒无操作自动跳转」,核心是3个配置和逻辑错误:

  • promptTimeout 参数值配置错误:当前写的1000 * 600000换算后约为167小时,远大于你需要的60秒阈值
  • 倒计时组件MyTimer的过期时间在组件首次渲染时就固定为600秒后,既没有和弹窗弹出时机绑定,过期回调也仅打印日志,没有关联跳转逻辑
  • navigate 方法定义在onIdle回调之后,存在引用风险,同时弹窗内的自定义倒计时和react-idle-timer内置的提示阶段计时完全不同步
修复步骤
  1. 修正超时配置,将弹窗弹出后的等待时长改为60秒
  2. 调整MyTimer组件,支持外部传入过期回调,移除写死的日志逻辑
  3. 新增状态存储弹窗倒计时的过期时间,仅在弹窗触发时动态生成60秒后的时间戳
  4. 调整跳转、关闭弹窗的相关逻辑,重置倒计时状态,避免时间戳复用导致的计时错误
  5. 移除组件内写死的固定过期时间变量
修正后完整代码
import React, { useState, useEffect } from "react";
import { useIdleTimer } from "react-idle-timer";
import { useTimer } from 'react-timer-hook';
import Modal from 'react-modal';
import NotFound from 'components/NotFound';
import { useNavigate } from 'react-router-dom';

function MyTimer({ expiryTimestamp, onExpire }) {
  const { seconds } = useTimer({ expiryTimestamp, onExpire });
  return <span>{seconds}</span>
}

function Application(props) {
  let {
    progress,
    setProgress,
    propertyInfo,
    bindSubmitForm,
    dispatchOpenModal,
    mainProfilingAnswer,
  } = props;

  const navigate = useNavigate();
  // 无操作触发弹窗的时长,当前为6秒,可按需调整
  const timeout = 1000 * 6 * 1;
  // 弹窗弹出后无操作自动跳转的等待时长:60秒
  const promptTimeout = 1000 * 60;

  const [open, setOpen] = useState(false);
  const [remaining, setRemaining] = useState(0);
  // 存储弹窗倒计时的过期时间
  const [promptExpireTime, setPromptExpireTime] = useState(null);

  const onPrompt = () => {
    setOpen(true);
    // 弹窗打开时动态生成60秒后的过期时间
    const expireTime = new Date();
    expireTime.setSeconds(expireTime.getSeconds() + 60);
    setPromptExpireTime(expireTime);
    setRemaining(promptTimeout / 1000);
  };

  const onIdle = () => {
    navigate('/notfound');
    setOpen(false);
    setPromptExpireTime(null);
    setRemaining(0);
  };

  const onActive = () => {
    setOpen(false);
    setPromptExpireTime(null);
    setRemaining(0);
  };

  const { getRemainingTime, isPrompted, activate } = useIdleTimer({
    timeout,
    promptTimeout,
    onPrompt,
    onIdle,
    onActive,
  });

  const handleStillHere = () => {
    setOpen(false);
    setPromptExpireTime(null);
    activate();
  };

  useEffect(() => {
    const interval = setInterval(() => {
      if (isPrompted()) {
        setRemaining(Math.ceil(getRemainingTime() / 1000));
      }
    }, 1000);
    return () => {
      clearInterval(interval);
    };
  }, [getRemainingTime, isPrompted]);

  function afterOpenModal() {}

  function closeModal() {
    navigate('/notfound')
    setOpen(false);
    setPromptExpireTime(null);
  }

  return (
    <>
      <div className="mt-5 md:mt-0 md:col-span-2">
        <Modal
          isOpen={open}
          onAfterOpen={afterOpenModal}
          onRequestClose={closeModal}
          style={customStyles}
          contentLabel="Example Modal"
        >
          <div className="Path"><img src={Iconn} /></div>
          <h2 className="Are-you-there">Are you there </h2>
          <p>Due to inactive, you will be redirected {promptExpireTime ? <MyTimer expiryTimestamp={promptExpireTime} onExpire={closeModal} /> : 60} seconds. 
            Click “Yes” to stay, click “No” to leave.</p>
          <div className="btnwrap">
            <button className="button" onClick={closeModal}>
              No
            </button>
            <button className="button" onClick={handleStillHere}><span className="Yes">Yes</span></button>
          </div>
        </Modal>
        <div className="">
          some thing goes here
        </div>
      </div>
    </>
  );
}
补充说明

修复后两套计时逻辑(react-idle-timer内置的prompt超时、弹窗内显示的倒计时)完全同步,误差不超过1秒:如果用户点击「Yes」会重置空闲计时、关闭弹窗回到正常状态;点击「No」或者60秒内无任何操作,都会自动跳转到指定的/notfound页面。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 09:33:29