ReactJS — использование setTimeout() с оператором if/else

Я работаю над часами React pomodoro и застрял на соединении if/else с setTimeout(). Вот мой код:

React.useEffect(() => {
    if (props.isOn === true) {
      if (props.timeLeft <= 0) {
        setTimeout(function() {
          if (props.activeClockType === 'Session') {
            props.handleClockType('Break');
            props.handleTimeLeft(props.breakLength * 60);
          } else {
            props.handleClockType('Session');
            props.handleTimeLeft(props.sessionLength * 60);
          }
        }, 1000);
      }
      const id = setInterval(count, 1000);
      return () => clearInterval(id);
    }
  });

Когда часы идут к 00:00, они останавливаются на 1 секунду, а затем показывают перерыв, а таймер устанавливает значение breakLength. Отлично, но через 1 секунду обратный отсчет не начинается, а возвращается к сеансу и подсчитывается длина сеанса.

Когда я удаляю setTimeout (прокомментировано в CodePen), он работает хорошо, но он не останавливается в 00:00 на 1 секунду, а сразу же меняется на Break, что выглядит некрасиво.

Как заставить его остановиться в 00:00 на 1 секунду перед подсчетом других активных часов?

Я потратил весь вечер на поиски какой-либо подсказки, но до сих пор понятия не имею, что не так. Я пытался установить setTimeout во всех возможных комбинациях с if, но эффект всегда один и тот же. Из Эта тема я подозреваю, что мне, вероятно, следует использовать clearTimeout, но также пробовал его в любой комбинации и ничего не получил.

Или, может быть, мне следует попробовать другую возможность запуска обратного отсчета, чем useEffect()? Ранее я сделал рабочий таймер в компоненте класса (прокомментировано в CodePen) с помощью componentWillReceiveProps, но он устарел, и мои попытки изменить его на других функциях ничего не дали. Я не до конца понимаю этот эффектный хук, но это был единственный способ, которым я нашел хорошо считал. И это короче, чем компонент класса.

Здесь — мой полный код на CodePen

Заранее спасибо.

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
0
1 666
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я думаю, что здесь есть две проблемы:

1) Каждый раз, когда вы используете хук для установки состояния, вы запускаете React.useEffect, если вы устанавливаете состояние дважды, React.useEffect будет запускаться дважды.

2) используйте setTimeout для замены setInterval, чтобы избежать слишком большого количества обновлений состояния.

Проблемы показаны ниже:

  React.useEffect(() => {
    if (props.isOn === true) {
      if (props.timeLeft <= 0 && !changeClockType) {
        setTimeout(function() {
          if (props.activeClockType === 'Session') {
            props.handleClockType('Break');   // ==> Fired update and then excuted React.useEffect
            props.handleTimeLeft(props.breakLength * 60); //  ==> Fired update again and then excuted React.useEffect again
          } else {
            props.handleClockType('Session');
            props.handleTimeLeft(props.sessionLength * 60);
          }
        }, 1000);
      }
      const id = setTimeout(count, 1000);  // ==> modify setInterval to setTimeout 
      return () => clearInterval(id);
    }

  });

Я пытаюсь изменить код следующим образом:

let changeClockType = false;  // ==> Should be put here because it couldn't be put in the function component
function Timer(props) {

  const count = () => props.handleTimeLeft(props.timeLeft - 1);

  function startStop() {
    props.handleIsOn(props.isOn === false ? true : false);
  }

  React.useEffect(() => {
    console.info("step 1");
    if (props.isOn === true) {   console.info("step 2");
      if (props.timeLeft <= 0 && !changeClockType) {   console.info("step 3");
        setTimeout(function() {
          if (props.activeClockType === 'Session') {   console.info("step 4");
            changeClockType = true;
            props.handleClockType('Break');   // ==> Fired update and then excuted React.useEffect
            console.info("Change to Break")
            props.handleTimeLeft(props.breakLength * 60); //  ==> Fired update again and then excuted React.useEffect again
            changeClockType = false;
            console.info("Set breakLength")
          } else {   console.info("step 5");
            changeClockType = true;
            props.handleClockType('Session');
            props.handleTimeLeft(props.sessionLength * 60);
            changeClockType = false;
          }
        }, 1000);
      }
      const id = setTimeout(count, 1000);  // ==> modify setInterval to setTimeout 
      return () => clearInterval(id);
    }
  });

Код не такой чистый, но его можно запустить.

Работает отлично! Спасибо большое.

Milo K 10.03.2019 21:07

Кстати, почему этот let объявлен вне функции? Я пробовал, и на самом деле он не работает, если он объявлен внутри. Он работает, если объявлен как хук useState. Что лучше нормальная декларация как у вас или хук?

Milo K 10.03.2019 21:13

Потому что, если changeClockType помещается в функцию Timer, когда выполняется реквизит.handleClockType('Перерыв'), будет выполняться функция Таймер, и значение changeClockType будет инициализировано. И после того, как функция Timer выполнена, будет выполнена реквизит.handleTimeLeft (реквизит.breakLength * 60). Вы можете попробовать код и просмотреть журнал в консоли.

tinwan 11.03.2019 04:18

Другие вопросы по теме