如何解决手动注销后重新登录时旧setTimeout未终止导致的自动注销重复跳转问题
解决重复导航问题:管理自动注销的定时器
你遇到的问题核心是每次登录都会创建一个新的setTimeout,但之前的定时器没有被清除,导致手动注销后旧定时器依然在后台运行,到期后触发重复导航。下面是具体的解决方案,一步步帮你修复这个问题:
1. 用useRef存储定时器ID
首先,在组件内部使用useRef来保存定时器的ID——它的优势是值会在组件的整个生命周期中保持不变,不会随着组件重新渲染而重置,非常适合存储这种跨渲染周期的变量:
import { useRef, useEffect } from 'react'; // 在组件内部声明 const timeoutRef = useRef(null);
2. 创建新定时器前清除旧的
在登录成功的回调中,先检查并清除之前可能存在的定时器,再创建新的定时器并把ID存入timeoutRef:
const onSubmitHandler = (e) => { e.preventDefault(); console.log(emailId); console.log(password); axios.post('http://localhost:8080/login', { emailId, password }) .then(response => { console.log(response); localStorage.setItem('token', response.data.token); axios.defaults.headers.common['Authorization'] = response.data.token; // 关键:清除之前未执行的定时器 if (timeoutRef.current) { clearTimeout(timeoutRef.current); } // 保存新的定时器ID timeoutRef.current = setTimeout(() => { localStorage.removeItem('token'); axios.defaults.headers.common['Authorization'] = null; navigate('/'); // 执行后清空ref,避免后续重复清除 timeoutRef.current = null; }, 60000); navigate('/'); }) .catch(err => { console.log(err.response.data.message); if (err.response.status === 500) { navigate('/500'); } setError(err.response.data.message); }) }
3. 手动注销时清除定时器
在你的手动注销函数中,也要加入清除定时器的逻辑,确保用户主动注销后,后台不会残留定时器:
const handleManualLogout = () => { // 清除定时器 if (timeoutRef.current) { clearTimeout(timeoutRef.current); timeoutRef.current = null; } // 执行注销操作 localStorage.removeItem('token'); axios.defaults.headers.common['Authorization'] = null; navigate('/'); }
4. 组件卸载时清除定时器(可选但推荐)
为了避免内存泄漏,在组件卸载时也要清除未执行的定时器,用useEffect的清理函数实现:
useEffect(() => { // 组件卸载时的清理逻辑 return () => { if (timeoutRef.current) { clearTimeout(timeoutRef.current); } }; }, []); // 空依赖数组确保只在组件挂载和卸载时执行
这样处理后,不管是登录时替换旧定时器,还是手动注销时主动清除,都能保证同一时间只有一个自动注销的定时器在运行,不会出现重复导航的问题了。
内容的提问来源于stack exchange,提问作者Pawan
相关产品推荐
相关产品推荐

