SetInterval в приложении React
Я все еще довольно новичок в React, но я медленно размалывал, и я столкнулся с чем-то, на что я застрял.
Я пытаюсь создать компонент "таймер" в React, и, честно говоря, я не знаю, буду ли я делать это правильно (или эффективно). В моем коде ниже я установил состояние, чтобы вернуть объект { currentCount: 10 }
и был связан с componentDidMount
, componentWillUnmount
и render
, и я могу получить только состояние "count down" от 10 до 9.
Вопрос из двух частей: что я ошибаюсь? И есть ли более эффективный способ использования setTimeout (вместо использования componentDidMount
и componentWillUnmount
)?
Спасибо заранее.
import React from 'react';
var Clock = React.createClass({
getInitialState: function() {
return { currentCount: 10 };
},
componentDidMount: function() {
this.countdown = setInterval(this.timer, 1000);
},
componentWillUnmount: function() {
clearInterval(this.countdown);
},
timer: function() {
this.setState({ currentCount: 10 });
},
render: function() {
var displayCount = this.state.currentCount--;
return (
<section>
{displayCount}
</section>
);
}
});
module.exports = Clock;
Ответы
Ответ 1
Я вижу 4 проблемы с вашим кодом:
- В вашем методе таймера вы всегда устанавливаете свой текущий счет 10
- Вы пытаетесь обновить состояние в методе рендеринга
- Вы не используете метод
setState
для фактического изменения состояния
- Вы не сохраняете свой интервал в состоянии
Попробуем исправить это:
componentDidMount: function() {
var intervalId = setInterval(this.timer, 1000);
// store intervalId in the state so it can be accessed later:
this.setState({intervalId: intervalId});
},
componentWillUnmount: function() {
// use intervalId from the state to clear the interval
clearInterval(this.state.intervalId);
},
timer: function() {
// setState method is used to update the state
this.setState({ currentCount: this.state.currentCount -1 });
},
render: function() {
// You do not need to decrease the value here
return (
<section>
{this.state.currentCount}
</section>
);
}
Это приведет к уменьшению таймера от 10 до -N. Если вы хотите, чтобы таймер уменьшался до 0, вы можете использовать слегка измененную версию:
timer: function() {
var newCount = this.state.currentCount - 1;
if(newCount >= 0) {
this.setState({ currentCount: newCount });
} else {
clearInterval(this.state.intervalId);
}
},
Ответ 2
Обновлен 10-секундный обратный отсчет с использованием class Clock extends Component
import React, { Component } from 'react';
class Clock extends Component {
constructor(props){
super(props);
this.state = {currentCount: 10}
}
timer() {
this.setState({
currentCount: this.state.currentCount - 1
})
if(this.state.currentCount < 1) {
clearInterval(this.intervalId);
}
}
componentDidMount() {
this.intervalId = setInterval(this.timer.bind(this), 1000);
}
componentWillUnmount(){
clearInterval(this.intervalId);
}
render() {
return(
<div>{this.state.currentCount}</div>
);
}
}
module.exports = Clock;
Ответ 3
Обновлен 10-секундный обратный отсчет с использованием хуков (новое предложение функций, позволяющее использовать состояние и другие возможности React без написания класса. В настоящее время они находятся в React v16.7.0-alpha).
import React, { useState, useEffect } from 'react';
import ReactDOM from 'react-dom';
const Clock = () => {
const [currentCount, setCount] = useState(10);
const timer = () => setCount(currentCount - 1);
useEffect(
() => {
if (currentCount <= 0) {
return;
}
const id = setInterval(timer, 1000);
return () => clearInterval(id);
},
[currentCount]
);
return <div>{currentCount}</div>;
};
const App = () => <Clock />;
ReactDOM.render(<App />, document.getElementById('root'));
Ответ 4
Спасибо @dotnetom, @greg-herbowicz
Если он возвращает "this.state не определено" - функция таймера привязки:
constructor(props){
super(props);
this.state = {currentCount: 10}
this.timer = this.timer.bind(this)
}
Ответ 5
Попробуйте этот код, надеюсь, что это поможет, если есть что-нибудь, что я могу вам помочь, ответьте мне.
https://jscomplete.com/repl/?j=H1h8vMLtb
class Clock extends React.Component {
state = {
myCounter: 0,
};
componentDidMount() {
setInterval(() => {
this.setState({ myCounter: this.state.myCounter+1 })
}, 1000);
}
render() {
return (
<div>
<p>{this.state.myCounter}</p>
</div>
);
}
}
ReactDOM.render(<Clock />, mountNode);