簡體   English   中英

React 中的 setTimeout 和 clearTimeout

[英]setTimeout and clearTimeout in React

當用戶使用 setTimeout 和 clearTimeout 在頁面上 30 秒內未進行任何點擊事件時,我正在努力創建注銷功能。

但是每次用戶點擊頁面上的任何東西時,剩余時間必須重新設置為 30 秒(或者作為另一個選項,將使用 clearTimeOut 和 setTimeOut。)同時當用戶沒有點擊頁面上的任何東西時,他們將在 30 秒后通過刪除 accessToken 自動注銷。

所以要解決這個問題,我的做法是這樣的:

  • 當用戶來到這個頁面時,setTimeout() 將開始。

  • 當用戶單擊頁面上的某些內容時,clearTimeOut 將處於活動狀態並且 setTimeOut 也將再次處於活動狀態

  • 當用戶在 30 秒內沒有點擊頁面上的任何內容時,他們將通過刪除本地存儲中的 accessToken 自動注銷

目前通過刪除 accessToken 使用戶在 30 秒后注銷。 UseEffect 中的 setTimeOut 也有效。

唯一的問題是當用戶在頁面上進行點擊事件時,我不知道如何使 clearTimeOut() 和 setTimeOut 工作。

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;

你可以做這樣的事情。 因此,您運行計時器,每次單擊文檔中的某處時,它都會取消當前計時器並運行新計時器。 因此,僅當用戶在 N 秒后未單擊該頁面時,您的myFunc function 才會運行。

請記住,你想在 30 秒內完成,你需要將 30000 放入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)
    }
  }, [])

從您的代碼片段中跳出幾個問題:

  1. timeoutBegins的范圍僅限於您的useEffect回調,因此不可用於clickDisplay
  2. clickDisplay未附加到任何事件偵聽器
  3. timeoutBegins不可調用,它是定時器 ID

注意:創建一個最小的可重現示例是個好主意,因為這將幫助您和審閱者消除問題。

解決方案:

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>;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM