我是ReactJS和javascript的初学者
我问了一个关于How can I setState on two array elements at once?
的问题在那个问题上,响应者告诉我无论如何都不要改变状态。
但我有另一个问题,如果我想在计时器到达0时使用clearInterval()
停止倒数计时器。
在我对codePen Timer Demo 2的新尝试中,
我使用find()
方法查找时间为0的元素,并使用clearInterval
来停止倒计时,但如果一个元素的时间到达0而另一个元素的时间不到,都停了。
我该如何解决?
const timers = [
{
id: 1,
time: 5,
timeIsUp: false,
},
{
id: 2,
time: 10,
timeIsUp: false,
},
];
class Clock extends React.Component {
constructor(props) {
super(props);
this.state= {
timers,
}
this.time_controller = 0;
}
componentDidMount(){
this.time_controller = setInterval(() =>{
this.countDown();
}, 1000)
}
countDown(){
const foundTimers = this.state.timers.map(timer => ({
...timer,
time: timer.time-1
}));
this.setState({timers: foundTimers});
const foundTimer = foundTimers.find(timer => timer.time === 0 );
if(!!foundTimer){
clearInterval(this.time_controller);
}
}
renderTimers(){
return(
this.state.timers.map((timer) =>{
return(
<div key = {timer.id} >
<div>{timer.time}</div>
</div>
)
})
)
}
render() {
return (
<div>
{this.renderTimers()}
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
答案 0 :(得分:3)
这与国家管理无关,这是一个简单的逻辑:
旁注:timeIsUp
标志确实没有任何理由,是吗? time === 0
表示时间到了,不是吗?复制状态为您在一个地方更新它而不是其他地方的错误打开了大门。
这些方面的东西,但细节并不像概念那样重要:
countDown() {
let updated = false;
let keepTicking = false;
const updatedTimers = this.state.timers.map(timer => {
// Note that if we don't modify `timer`, we return it for reuse
if (timer.time > 0) {
timer = {...timer, time: timer.time - 1};
updated = true;
keepTicking = timer.time > 0;
}
return timer;
});
if (updated) {
// We changed somthing, update
this.setState({timers: updatedTimers});
}
if (this.time_controller !== 0 && !keepTicking) {
// No more active timers, stop ticking
clearInterval(this.time_controller);
this.time_controller = 0;
}
}
请注意,当我们清除计时器时,我会清除计时器手柄,因此我们知道它是否正在运行。
请注意,在该示例中,我采用带有副作用的map
回调的实用方法(设置updated
和keepTicking
标志)。我没有像这样的局部副作用的问题,但是那里有一个重要的运动。
非副作用版本至少会部分循环定时器:
countDown() {
const timers = this.state.timers;
// Need to update?
if (timers.find(t => t.time > 0)) {
const updatedTimers = timers.map(timer => (
// If we don't change a timer, we can reuse it
timer.time === 0 ? timer : {...timer, time: timer.time - 1}
);
this.setState({timers: updatedTimers});
}
// Done ticking?
if (this.time_controller !== 0 && updatedTimers.every(t => t.time === 0)) {
clearInterval(this.time_controller);
this.time_controller = 0;
}
}
请注意代码是如何更清晰(因为我们只在需要时表达我们自己做的每件事)但效率较低(我们可能必须努力找到接近需要更新的结束的计时器)并让我们滴答作响)。 90%的时间,效率并不重要,timers
将少于几千个条目。所以有一个论据。