Timer
определение функции не имеет this
класса, связанного с ним, поэтому, когда оно вызывает this.setState
, оно не совпадает this
с компонентом. У вас есть 2 варианта.
Опция 1: привязать this
к Timer
в конструкторе
constructor(props) {
super(props);
this.state = {
time: 1200,
timer: '',
};
this.Timer = this.Timer.bind(this);
}
Опция 2: использовать функцию стрелки ES6 для автоматического связывания этого с вызывающим абонентом
Timer = () => {...};
Примечание: имена функций, как правило, должны быть в camelCased, а не в PascalCased
Вы можете немного упростить логику вашего компонента c. Во-первых, отображаемое время может быть получено из числового значения состояния time
, поэтому нет необходимости хранить и то и другое. Во-вторых, похоже, что вы пытаетесь обновить время , а затем использовать это новое время для вычисления отображаемого времени. Обновления состояния реакции являются асинхронными, поэтому следующее значение состояния не будет доступно до следующего цикла рендеринга.
Просто обновите состояние в обратном вызове setInterval
и вычислите полученное время отображения в функции рендеринга.
Sleep.jsx
class Sleep extends Component {
state = {
time: 60 * 20 // 20 minutes
};
componentDidMount() {
this.interval = setInterval(
// functional state update to ensure state is correctly updated
// from previous state
() => this.setState(({ time }) => ({ time: time - 1 })),
1000
);
}
componentDidUpdate() {
const { time } = this.state;
if (time <= 0) {
clearInterval(this.interval);
}
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
const { time } = this.state;
const minutes = String(Math.floor(time / 60)).padStart(2, "0");
const seconds = String(time % 60).padStart(2, "0");
return (
<div>
{minutes}:{seconds}
</div>
);
}
}