因此,我遇到了这个问题,我不知道这是一个错误理解的概念还是该概念的错误实现。 我在freecodecamp.org中做番茄钟,这迫使我在纯js和React组件中使用setInterval()函数。
在Pomodoro组件内部,每次将其装入DOM树时,都应运行setInterval检查状态并根据组件的状态计时。实际上,我可以看到状态变量发生了变化(由于使用了React Debugging工具),但是间隔不起作用
componentdidmount在将组件呈现在DOM树中并检查state.status之后运行,如果其true则检查要运行的周期,是会话还是中断时钟。一个计时器结束后,另一个计时器应立即启动。
此计时器或间隔存储在组件状态中,然后从this.state.interval状态清除。
class Pomodoro extends React.Component {
constructor(props) {
super(props);
this.state = {
session:1500,
break:300,
cycle:true,
status:false,
sessionClock:1500,
breakClock:300,
interval:0,
}
this.addSessionTime = this.addSessionTime.bind(this);
this.decSessionTime = this.decSessionTime.bind(this);
this.addBreakTime = this.addBreakTime.bind(this);
this.decBreakTime = this.decBreakTime.bind(this);
this.pause = this.pause.bind(this);
this.reset = this.reset.bind(this);
}
/*Avoided all the other binded functions since they are just setStates*/
componentDidMount() {
if (this.state.status)
{
if (this.state.cycle /* cycle true = session */)
{
this.setState({
interval:(setInterval( ()=> {
if (!this.state.status/*status true = clock running*/ ) {clearInterval(this.state.interval);}
else
{/*begin session clock*/
if (this.state.sessionClock > 1 /*check if is the last second*/)
{
this.setState({sessionClock: this.state.sessionClock - 1});
/*take away a second from sessionClock*/
}
else {this.setState({cycle:!this.state.cycle, sessionClock:this.state.session}) }
} /*change cycle and restart sessionclock*/
}
,1000)
)})}
else /*cycle off = break time*/
{
this.setState({interval: setInterval(()=>{
if (!this.state.status) {clearInterval(this.state.interval)}
else {
/*begin break clock*/
if (this.state.breakClock > 1)
{this.setState({breakClock:this.state.breakClock - 1})}
else {this.setState({cycle:!this.state.cycle, breakClock:this.state.break})}
}
},1000)})
}
}
else { clearInterval(this.state.interval)}
}
由于将setInterval保存为Component状态或其他原因,时钟无法工作?
编辑
添加了一个代码笔,以便您可以看到实时版本和状态更改
https://codepen.io/bigclown/pen/bGEpJZb
EDIT II
删除了componentdidmount方法并将内容移至pause()方法,但是现在两个时钟同时运行,并且时钟运行得比预期的快(可能是由于react中的异步状态更新引起的问题?)
答案 0 :(得分:1)
问题是您使用componentDidMount
。在安装组件时调用它,这意味着在用户可以与屏幕交互之前调用它。
您的支票
if (this.state.status)
永远不会为真,因为您的状态会将status
设置为false。
查看您的代码,我假设您是说暂停按钮将状态切换为true,并且您认为componentDidMount
中的代码将运行。
但是,您应该做的是将代码移至pause()
函数中,因为这实际上是时钟的触发器。
从那里您可以执行以下操作:
pause() {
if (this.state.status === false) {
// Start your clock, whilst checking `cycle`
} else {
clearInterval(this.state.interval);
}
}
这是一个Codepen,我在其中重构了您的代码,但是基本上将所有逻辑都移到了Pause
中。 https://codepen.io/stephenyu-the-encoder/pen/zYrqQYE
我已将所有时钟更改为从5秒开始,以便更快地查看其工作情况。
答案 1 :(得分:0)
我怀疑您的时钟同时运行且计时器关闭是由于在启动新计时器之前未停止旧计时器造成的。
您可能正在寻找的是componentDidUpdate方法。使用此方法,您可以将上一个状态与当前状态进行比较,并进行相应的更改。使用该方法,您可以检查我们何时从休息时间切换到会话时间,然后停止旧计时器启动新计时器,如下所示:
componentDidUpdate(prevProps, prevState) {
// We need to check that the new state is different from the old state
// if it is, stop the old timer, and kick off the new one
if (prevState.cycle !== this.state.cycle) {
clearInterval(this.state.interval);
if (this.state.cycle) {
// If the cycle switched to session, start the session timer
this.startSession();
} else {
// If the cycle switched to break, start the break timer
this.startBreak();
}
}
}
通过这种方式,只要您的会话或中断计时器达到0并切换this.state.cycle
,您就永远可以启动新计时器。
查看我的新Codepen here,了解功能齐全的代码