[英]Prompt user before the session ends
I need to display a dialog box where it shows the remaining time for the current session to expire.我需要显示一个对话框,其中显示当前会话到期的剩余时间。 I have implemented it, unfortunately,the timer is ticking multiple times.Here is my code.
我已经实现了它,不幸的是,计时器正在滴答多次。这是我的代码。
warningTime
and timeout
value is fetched from the api which is in parent component. warningTime
timeout
和timeout
值是从父组件中的 api 获取的。
const [ remainingTime, setRemainingTime ] = useState(warningTime);
useEffect(() => {
let interval = null;
if (timeout > 0) {
let sessionTimeoutInterval = setInterval(() => {
let runTime = localStorage.getItem("timeout");
if (parseInt(runTime) === warningTime) {
openDialog();
if(remainingTime===warningTime) {
interval = setInterval(() => {
if (remainingTime > 0) {
setRemainingTime(remainingTime => remainingTime - 1);
}
}, 1000);
}
if(remainingTime === 0) {
handleDialogClose();
clearInterval(interval);
}
} else{
localStorage.setItem("timeout", --runTime);
}
}, 1000);
if (remainingTime === 0) {
handleDialogClose();
handleLogout();
}
return () => {
clearInterval(sessionTimeoutInterval);
};
}
}, [timeout, remainingTime, warningTime ]);
remainingTime
will be displayed in dialog. remainingTime
将显示在对话框中。
I have made couple of change in the code.我在代码中做了一些更改。
useRef
to hold the status of the component.useRef
来保存组件的状态。 So in useEffect
i am checking if the component is mounted and then setting the timer value from the localStorage
or from the props
value and on subsequent updates useEffect
will not execute the code inside if (init.current)
block.useEffect
我正在检查组件是否已安装,然后从localStorage
或props
值设置计时器值,并且在后续更新中useEffect
将不会执行if (init.current)
块内的代码。useRef returns a mutable ref object whose .current property is initialized to the passed argument (initialValue).
useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传递的参数 (initialValue)。 The returned object will persist for the full lifetime of the component
返回的对象将在组件的整个生命周期内持续存在
Note useRef doesn't notify you when its content changes.
注意 useRef 不会在其内容更改时通知您。 Mutating the .current property doesn't cause a re-render.
改变 .current 属性不会导致重新渲染。
setTimeout
to update the sessionTimeout
state after every 1 second to update the timer, so the state update will execute the useEffect
hook after each update as the sessionTimeout
in included in the useEffect
dependency.setTimeout
在每 1 秒后更新sessionTimeout
状态以更新计时器,因此状态更新将在每次更新后执行useEffect
挂钩,因为sessionTimeout
包含在useEffect
依赖项中。 Try this.尝试这个。
import React, { useEffect, useState, useRef } from "react";
import DialogBox from "./DialogBox";
import Logout from "./Logout";
export default function Child({ warningTime, timeout }) {
const [showDialog, setShowDialog] = useState(false);
const [showLogout, setShowLogout] = useState(false);
const [sessionTimeout, setSessionTimeout] = useState(timeout);
const init = useRef(true);
const progressbar = useRef(warningTime);
useEffect(() => {
if (init.current) {
init.current = false;
let sessionTime = localStorage.getItem("timeout");
if (sessionTime && sessionTime < warningTime) {
progressbar.current = sessionTime;
} else {
progressbar.current = warningTime;
}
if (sessionTime) {
setSessionTimeout(prevState => sessionTime);
} else {
localStorage.setItem("timeout", sessionTimeout);
}
}
let sessionTimeoutInterval = null;
if (sessionTimeout > 0) {
sessionTimeoutInterval = setTimeout(() => {
if (sessionTimeout <= warningTime) {
openDialog();
}
setSessionTimeout(sessionTimeout => {
let updatedtime = sessionTimeout - 1;
localStorage.setItem("timeout", updatedtime);
return updatedtime;
});
}, 1000);
} else {
localStorage.removeItem("timeout");
handleDialogClose();
handleLogout();
clearTimeout(sessionTimeoutInterval);
}
return () => {
if (sessionTimeoutInterval) clearTimeout(sessionTimeoutInterval);
};
}, [sessionTimeout]);
function openDialog() {
setShowDialog(true);
}
function handleDialogClose() {
setShowDialog(false);
}
function handleLogout() {
setShowLogout(true);
}
function addMoreTimeHandler() {
handleDialogClose();
setSessionTimeout(sessionTimeout => {
localStorage.setItem("timeout", timeout);
return timeout;
});
}
return (
<div>
{showLogout ? <Logout /> : "Time remaning: " + sessionTimeout}
{showDialog ? (
<DialogBox
progressBar={progressbar.current - 1}
sessionTimeout={sessionTimeout}
addMoreTime={addMoreTimeHandler}
/>
) : null}
</div>
);
}
Live Example现场示例
I tried to simulate your code with dummy data and it worked.
let [ remainingTime, setRemainingTime, sessionTimeout, warningTime] = [1000, 5000, 10000, 1000];
let runTime = 3000;
function abc() {
let interval = null;
if (sessionTimeout > 0) {
let sessionTimeoutInterval = setInterval(() => {
if (parseInt(runTime) === warningTime) {
// openDialog();
console.log("open dialog");
if(remainingTime===warningTime) {
interval = setInterval(() => {
if (remainingTime > 0) {
remainingTime -= 1000;
}
}, 1000);
}
if(remainingTime === 0) {
// handleDialogClose();
console.log("close dialog");
clearInterval(interval);
clearInterval(sessionTimeoutInterval);
}
} else {
if(runTime > 0){ // this condition is newly added
runTime-=1000; }
}
}, 1000);
}
}
abc();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.