reactjssettimeoutlogoutmouseclick-eventcleartimeout

setTimeout and clearTimeout in React


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:

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;

Solution

  • 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)
        }
      }, [])