Я работаю над часами 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
Заранее спасибо.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Я думаю, что здесь есть две проблемы:
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);
}
});
Код не такой чистый, но его можно запустить.
Кстати, почему этот let объявлен вне функции? Я пробовал, и на самом деле он не работает, если он объявлен внутри. Он работает, если объявлен как хук useState. Что лучше нормальная декларация как у вас или хук?
Потому что, если changeClockType помещается в функцию Timer, когда выполняется реквизит.handleClockType('Перерыв'), будет выполняться функция Таймер, и значение changeClockType будет инициализировано. И после того, как функция Timer выполнена, будет выполнена реквизит.handleTimeLeft (реквизит.breakLength * 60). Вы можете попробовать код и просмотреть журнал в консоли.
Работает отлично! Спасибо большое.