React使用react-idle-timer实现弹窗后60秒无操作跳转页面
问题排查
你的现有代码无法实现「弹窗弹出后60秒无操作自动跳转」,核心是3个配置和逻辑错误:
promptTimeout参数值配置错误:当前写的1000 * 600000换算后约为167小时,远大于你需要的60秒阈值- 倒计时组件
MyTimer的过期时间在组件首次渲染时就固定为600秒后,既没有和弹窗弹出时机绑定,过期回调也仅打印日志,没有关联跳转逻辑 navigate方法定义在onIdle回调之后,存在引用风险,同时弹窗内的自定义倒计时和react-idle-timer内置的提示阶段计时完全不同步
修复步骤
- 修正超时配置,将弹窗弹出后的等待时长改为60秒
- 调整
MyTimer组件,支持外部传入过期回调,移除写死的日志逻辑 - 新增状态存储弹窗倒计时的过期时间,仅在弹窗触发时动态生成60秒后的时间戳
- 调整跳转、关闭弹窗的相关逻辑,重置倒计时状态,避免时间戳复用导致的计时错误
- 移除组件内写死的固定过期时间变量
修正后完整代码
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
相关产品推荐
相关产品推荐

