Запрос пользователя до окончания сеанса - PullRequest
1 голос
/ 05 февраля 2020

Мне нужно отобразить диалоговое окно, где оно показывает оставшееся время до истечения текущего сеанса. Я реализовал это, к сожалению, таймер работает несколько раз. Вот мой код.

warningTime и 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 будет отображаться в диалоговом окне.

Ответы [ 2 ]

1 голос
/ 05 февраля 2020

Я сделал пару изменений в коде.

  1. Я использую useRef для хранения статуса компонента. Таким образом, в useEffect я проверяю, смонтирован ли компонент, а затем устанавливаю значение таймера из localStorage или из значения props и при последующих обновлениях useEffect не выполнит код внутри блока if (init.current).

useRef возвращает изменяемый объект ref, свойство .current которого инициализируется переданным аргументом (initialValue). Возвращенный объект будет сохраняться в течение всего времени жизни компонента

Примечание. UseRef не уведомляет вас об изменении своего содержимого. Отключение свойства .current не вызывает повторного рендеринга.

Я использую setTimeout для обновления состояния sessionTimeout через каждую 1 секунду, чтобы обновить таймер, поэтому обновление состояния будет выполнять ловушку useEffect после каждого обновления, поскольку sessionTimeout входит в useEffect зависимость.

Попробуйте это.

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


Живой пример

Edit Prompt user before the session ends

0 голосов
/ 05 февраля 2020
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();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...