Reputation: 2087
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.
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.
Upvotes: 1
Views: 171
Reputation: 10569
I have made couple of change in the code.
useRef
to hold the status of the component. 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.useRef returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component
Note useRef doesn’t notify you when its content changes. Mutating the .current property doesn’t cause a re-render.
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.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
Upvotes: 1
Reputation: 227
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();
Upvotes: 0