Как установить и очистить интервал с помощью функции переключения в реакции с крючками? - PullRequest
0 голосов
/ 06 ноября 2019

Я пытаюсь построить таймер, который запускается одной кнопкой с функцией handleToggle , которая выглядит следующим образом:

const handleToggle = () => {
    let timer = () => setInterval(() => {
      dispatch({ type: "COUNT", payload: Date.now() - startTime });
    }, 100);
    const startTime = Date.now() - AppState.runningTime;
    if (AppState.countingStarted) {
      dispatch({
        type: "COUNTING_STARTED",
        payload: false
      });
      clearInterval(timer());
    } else {
      timer()
      dispatch({ type: "COUNTING_STARTED", payload: true });
    }
  };

COUNTING_STARTED отправкафункция, которая переключает AppState.countingStarted .

Я борюсь с остановкой таймера, как очистить этот интервал таймера? Я пытался:

const handleToggle = () => {
    let timer;
    if (AppState.countingStarted) {
      dispatch({
        type: "COUNTING_STARTED",
        payload: false
      });
      clearInterval(timer);
    } else {
      timer = setInterval(() => {
        dispatch({ type: "COUNT", payload: Date.now() - startTime });
      }, 100);
      const startTime = Date.now() - AppState.runningTime;
      dispatch({ type: "COUNTING_STARTED", payload: true });
    }
  };

но разницы нет ...

Ответы [ 2 ]

0 голосов
/ 06 ноября 2019

Пара вещей: то, что вы передаете clearInterval, должно быть возвращаемым значением от setInterval;в первом примере вы передаете ему свою собственную функцию. Второй пример имеет это право, но вы сохраняете timer (результат вызова setInterval) в области действия функции переключения, что означает, что после завершения функции вы теряете ссылку на нее;в следующий раз, когда вы вызываете функцию (например, чтобы остановить ее), вы переопределяете timer, а это не то, что вам нужно.

Все, что вам нужно, - это сохранить переменную timer в области, где она будет сохраняться. Например:

let timer = null;

const handleToggle = () => {
  if (AppState.countingStarted) {
    dispatch({
      type: "COUNTING_STARTED",
      payload: false
    });
    clearInterval(timer);
  } else {
    timer = setInterval(() => {
      dispatch({ type: "COUNT", payload: Date.now() - startTime });
    }, 100);
    const startTime = Date.now() - AppState.runningTime;
    dispatch({ type: "COUNTING_STARTED", payload: true });
  }
};

Эта функция может вызываться несколько раз;переменная timer будет сохраняться повсюду.

0 голосов
/ 06 ноября 2019

В вашем примере ссылка на intervalId теряется в конце выполнения функции.

Вы должны использовать переменную экземпляра для хранения intervalId. Если у вас есть компонент Class, вы можете использовать следующий код:

handleToggle = () => {
  // clear the interval, no matter the value of AppState.countingStarted
  // this prevent from recreating the interval multiple times
  clearInterval(this.timerId);

  if (AppState.countingStarted) {
     dispatch({type: "COUNTING_STARTED",payload: false});   
  } else {
    // store the timer id in an instance variable
    this.timerId = setInterval(() => {
      dispatch({ type: "COUNT", payload: Date.now() - startTime });
    }, 100);

    dispatch({ type: "COUNTING_STARTED", payload: true });
}

Если вы находитесь в компоненте Function, вы можете использовать ловушку useRef , чтобы получить то же самоеповедение:

const timerIdRef = useRef(null);

const handleToggle = () => {
  clearInterval(timerIdRef.current);

  if (AppState.countingStarted) {
     dispatch({type: "COUNTING_STARTED",payload: false});   
  } else {
    // store the interval id into the current property
    timerIdRef.current = setInterval(() => {
      dispatch({ type: "COUNT", payload: Date.now() - startTime });
    }, 100);

    dispatch({ type: "COUNTING_STARTED", payload: true });
}
...