react: почему не изменяются состояния компонента
Есть компонент со таймером обратного отсчёта от Ant Design (Statistic.Countdown).
Хотя, чтоб в зависимости от того сколько времени осталось до 0 он отрисовывался в разных стилях.
Делаю следующий код:
import { useState } from 'react';
import { Statistic } from 'antd';
const Header = (props) => {
// контроль состояний
const [timerState, setTimerState] = useState(0);
// стили для разных состояний
const styles = [
{deadline: 10, style: {color: '#000000', textAlign: 'center'}},
{deadline: 5, style: {color: '#bb0000', textAlign: 'center'}},
{deadline: 0, style: {color: '#bb0000', textAlign: 'center', animation: 'neon 1s infinite'}}
]
// колбэк: изменение времени таймера
const handleChangeTimer = (timer) => {
if (timer <= 1000 * styles[timerState]?.deadline) {
setTimerState(timerState + 1);
}
}
// отрисовать компонент
const currentStyle = styles[states.timer_state < styles.length ? states.timer_state : styles.length - 1].style;
return (
<Statistic.Countdown title='Время выполнения' value={props.timer} format='mm:ss' valueStyle={currentStyle} onChange={handleChangeTimer} />
);
}
В результате handleChangeTimer регулярно вызывается, timer уменьшается, setTimerState вызывается, а вот timerState никак не меняется и остается на одном значении (0).
В чем может быть дело?
Кстати если при этом как-то тормошить Statistic.Countdown, например там же устанавливать через новое состояние ему value, то setTimerState начинает работать. Например:
// контроль состояний
const [timerState, setTimerState] = useState({
state: 0,
deadline: props.timer
});
// колбэк: изменение времени таймера
const handleChangeTimer = (timer) => {
if (timer <= 1000 * styles[timerState]?.deadline) {
setTimerState({
timerState.state: timerState + 1,
deadline: Date.now() + timer);
}
}
return (
<Statistic.Countdown title='Время выполнения' value={timerState.deadline} format='mm:ss' valueStyle={currentStyle} onChange={handleChangeTimer} />
);
Почему так?
Ответы (1 шт):
Автор решения: Armen
→ Ссылка
предлагаю пользоватся так, а не через свой стейт (то есть следить за таймером исключительно)
что касается проблемы:
внутри Countdown используется setInterval что в свою очередь замыкает переменную timerState. по этому она всегда 0
то что у них под капотом написано ведет к тому что timerState должен быть состоянием и изменение этого состояния внутри handleChangeTimer должно тригернуть на вызов onChange уже с актуальным timerState НО каким значением обновить timerState что то не особо понятно. (как не пробовал у меня секунды тикали в х3 скорости)
const Header = () => {
const [timerState] = useState(Date.now() + timeout);
const [deadline, setDeadline] = useState(7);
const styles = {
7: {
color: 'green',
},
5: {
color: 'blue',
},
3: {
color: 'red',
},
};
const handleChangeTimer = (timer: number) => {
const roundedTimer = Math.round(timer / 1000);
if (styles[roundedTimer]) {
setDeadline(roundedTimer);
}
};
const currentStyle = styles[deadline];
return (
<Statistic.Countdown
title="Время выполнения"
value={timerState}
format="mm:ss"
valueStyle={currentStyle}
onChange={handleChangeTimer}
/>
);
};