我有一个需要空闲超时的应用程序,该应用程序首先警告用户他们将在一分钟后注销,然后在一分钟后将用户注销。
我在使用类组件方面取得了成功,如以下博文所示:
Session timeout warning modal using react
我正在将应用程序代码移到React Hooks上,但是我很难移开该代码。我尝试了以下方法:
const [signoutTime, setSignoutTime] = useState(0);
let warnTimeout;
let logoutTimeout;
const setTimeout = () => {
warnTimeout = setTimeout(warn, warningTime);
logoutTimeout = setTimeout(logout, signoutTime);
};
const clearTimeout = () => {
if (warnTimeout) clearTimeout(warnTimeout);
if (logoutTimeout) clearTimeout(logoutTimeout);
};
useEffect(() => {
setWarningTime(10000);
setSignoutTime(15000);
const events = [
'load',
'mousemove',
'mousedown',
'click',
'scroll',
'keypress'
];
const resetTimeout = () => {
clearTimeout();
setTimeout();
};
for (var i in events) {
window.addEventListener(events[i], resetTimeout);
}
setTimeout();
});
const warn = () => {
console.log('Warning');
};
const destroy = () => {
console.log('Session destroyed');
};
最后,我希望出现一个模式来警告用户即将退出。如果用户移动鼠标,单击等(见事件),则计时器重置。如果用户单击模式中的按钮,计时器将重置。
非常感谢您的帮助!
答案 0 :(得分:4)
尝试
mport React, { useEffect, useState } from 'react';
const LogoutPopup = () => {
const [signoutTime, setSignoutTime] = useState(10000);
const [warningTime, setWarningTime] = useState(15000);
let warnTimeout;
let logoutTimeout;
const warn = () => {
console.log('Warning');
};
const logout = () => {
console.log('You have been loged out');
}
const destroy = () => {
console.log('Session destroyed');
}
const setTimeouts = () => {
warnTimeout = setTimeout(warn, warningTime);
logoutTimeout = setTimeout(logout, signoutTime);
};
const clearTimeouts = () => {
if (warnTimeout) clearTimeout(warnTimeout);
if (logoutTimeout) clearTimeout(logoutTimeout);
};
useEffect(() => {
const events = [
'load',
'mousemove',
'mousedown',
'click',
'scroll',
'keypress'
];
const resetTimeout = () => {
clearTimeouts();
setTimeouts();
};
for (let i in events) {
window.addEventListener(events[i], resetTimeout);
}
setTimeouts();
return () => {
for(let i in events){
window.removeEventListener(events[i], resetTimeout);
clearTimeouts();
}
}
},[]);
return <div></div>
}
export default LogoutPopup;
答案 1 :(得分:2)
我稍微重写了您的答案以消除初始化错误,我认为将其提取到钩子中也很方便,因此您只需要传递所需的参数即可,而无需具有状态计时器。
我认为useCallback是为了提高效率,以使其停止在每个渲染器上正常工作
我已经在UseEffect中移动了其他一些东西,以消除这些掉毛错误!
import React, { useCallback } from 'react'
function useMonitor({ timeout, warningTimeout, onWarn, onTimeOut }) {
const warn = useCallback(()=> {
onWarn && onWarn()
},[onWarn])
const logout = useCallback(()=> {
onTimeOut && onTimeOut()
},[onTimeOut])
React.useEffect(() => {
let warnTimeout;
let logoutTimeout;
const setTimeouts = () => {
warnTimeout = setTimeout(warn, warningTimeout);
logoutTimeout = setTimeout(logout, timeout);
};
const clearTimeouts = () => {
if (warnTimeout) clearTimeout(warnTimeout);
if (logoutTimeout) clearTimeout(logoutTimeout);
};
const events = [
'load',
'mousemove',
'mousedown',
'click',
'scroll',
'keypress'
];
const resetTimeout = () => {
clearTimeouts();
setTimeouts();
};
for (let i in events) {
window.addEventListener(events[i], resetTimeout);
}
setTimeouts();
return () => {
for (let i in events) {
window.removeEventListener(events[i], resetTimeout);
clearTimeouts();
}
}
}, [logout, timeout, warn, warningTimeout]);
}
export default useMonitor
答案 2 :(得分:2)
基于第一个答案,当您还需要用户注销之前的时间时,我还有另一个钩子解决方案。
useAutoLogout.js
import React, { useEffect, useState } from "react";
const useLogout = (startTime) => {
const [timer, setTimer] = useState(startTime);
useEffect(() => {
const myInterval = setInterval(() => {
if (timer > 0) {
setTimer(timer - 1);
}
}, 1000);
const resetTimeout = () => {
setTimer(startTime);
};
const events = [
"load",
"mousemove",
"mousedown",
"click",
"scroll",
"keypress"
];
for (let i in events) {
window.addEventListener(events[i], resetTimeout);
}
return () => {
clearInterval(myInterval);
for (let i in events) {
window.removeEventListener(events[i], resetTimeout);
}
};
});
return timer;
};
export default useLogout;
App.js
import useAutoLogout from "./useAutoLogout";
function App() {
const timer = useAutoLogout(10);
if (timer == 0) {
return <div>Logged Out</div>;
}
if (timer < 8) {
return <div>In {timer} seconds you will be automatically logged out</div>;
}
return <div>Signed in</div>;
}
export default App;