I'm struggling with creating a logout feature when users don't make any click event for 30 seconds on the page using setTimeout and clearTimeout.
But every time the users click anything on the page, the remaining time must be reset to 30 seconds again( or as an another option, clearTimeOut and setTimeOut will be used.) Meanwhile when the users don't click anything on the page, they are gonna be logged out automatically after 30seconds by removing the accessToken.
So to resolve the problem, my approach is like this:
setTimeout() will be begun when the users come over to this page.
when the users click something on the page, clearTimeOut will be active and setTimeOut will be active again too
when the users don't click anything on the page for 30 seconds, they are gonna be logged out automatically by removing the accessToken in the local storage
Currently making the users logged out after 30seconds by removing the accessToken works! and setTimeOut in UseEffect works too.
The only matter is I have no idea how to make clearTimeOut() and setTimeOut work when the users make click event on the page..
import styled from 'styled-components';
import React, {useRef, useEffect, useState} from 'react';
import ScreenContainer from '../../src/component/common/ScreenContainer';
import {useNavigate as useDomNavigate} from 'react-router-dom';
import isNil from 'lodash/isNil';
import userClient from '../../src/client/user/userClient';
const Device = () => {
const domNavigate = useDomNavigate();
const [storeId, setStoreId] = useState(() => JSON.parse(localStorage.getItem('storeId')));
const [currentDeposit, setCurrentDeposit] = useState<number>(0);
const depositBalanceInfo = userClient.getDepositBalanceByStoreId(storeId, isNil(storeId)).data;
const [time, setTime] = useState(1500);
const logout = () => {
localStorage.removeItem('accessToken');
domNavigate(`/home/home`);
};
//////////////////////////
// below is the code that I wrote to make it work..
const myFunc = () => {
// remove accessToken for logout
localStorage.removeItem('accessToken');
// move to home page
domNavigate(`/home/home`);
}
// begin setTimeOut automatically when the users come over to this page from another one.
useEffect(() => {
const timeoutBegins = window.setTimeout(myFunc, 3000);
return () => clearTimeout(timeoutBegins);
}, [])
// when the users click anything on the page, it clears current setTimeOut function and restart the setTimeOut function again.
const clickDisplay = () => {
clearTimeout(timeoutBegins);
timeOutBegins();
}
/////////////////////////////////////////
useEffect(() => {
if (storeId && depositBalanceInfo) {
setCurrentDeposit(depositBalanceInfo?.depositBalance);
}
}, [storeId, depositBalanceInfo?.depositBalance]);
return (
<ScreenContainer>
<Wrapper>
<div>Choose Payment Option</div>
<button onClick={() => window.history.back()}>go back</button>
<div>Your Balance: {currentDeposit.toLocaleString()}dollar</div>
<br />
<button onClick={() => domNavigate(`/charge/step2-select-price/?chargeMethod=card`)}>Credit Card Payment</button>
<br />
<button onClick={() => domNavigate(`/charge/step2-select-price/?chargeMethod=cash`)}>Cash Payment</button>
<br />
<button onClick={() => domNavigate(`/home/checkUserByPin`)}>Reset Password</button>
<br />
<button onClick={logout}>Logout</button>
</Wrapper>
</ScreenContainer>
);
};
const Wrapper = styled.div`
border: 1px solid red;
`;
export default Device;
CodePudding user response:
There's a couple of issues that jump out from your snippet:
timeoutBegins
is scoped to youruseEffect
callback so isn't available toclickDisplay
.clickDisplay
is not attached to any event listenerstimeoutBegins
is not callable, it is the timer ID
Note: it's a good idea to create a minimal reproducable example as this will help both you and reviewers eliminate the problem.
Solution:
let timerId;
function Device() {
const logOutUser = () => {
// log out code...
};
const startTimer = () => {
if (timerId) clearTimeout(timerId);
timerId = setTimeout(logOutUser, 3000);
}
const stopTimer = () => clearTimeout(timerId);
useEffect(() => {
// start timer when component is mounted
startTimer();
// stop timer when component is unmounted
return stopTimer;
}, []);
return <div onClick={startTimer}></div>;
}
CodePudding user response:
You could do something like this. So, you run the timer and every time you clicking somewhere in the document it will cancel the current timer and run the new. So your myFunc
function will run only if user doesn't click on the page after N seconds.
Keep in mind, you want to do it in 30 sec you will need to put 30000 in setTimeout
const timerId = useRef(null)
const myFunc = () => {
clearTimeout(timerId.current)
timerId.current = null
console.log('DO SOMETHING')
}
const onDocumentClick = () => {
if (timerId.current) {
clearTimeout(timerId.current)
timerId.current = window.setTimeout(myFunc, 3000)
}
}
useEffect(() => {
timerId.current = window.setTimeout(myFunc, 3000)
document.addEventListener('click', onDocumentClick)
return () => {
clearTimeout(timerId.current)
document.removeEventListener('click', onDocumentClick)
}
}, [])