我正在尝试将pomodoro clock作为FreeCodeCamp的练习项目。这是一个简单的时钟,每当当前计时器结束时,它就会在会话时间和休息时间之间切换。
我正在面对与redux反应有关的问题。这是我的应用程序启动时的状态。
当我单击减号或加号时,存储中的计时器和会话/中断时间将相应更新,但这没有发生。会话/中断长度已更新,但计时器反映了先前的值。这是反映我增加会话时问题的屏幕截图
这是我的代码,对此负责
updateSettings(type) {
if (!this.props.isPlaying) {
let isInvalid = false; // to show alert if user input is invalid
if (type === 'increase-session') {
this.props.increaseSession();
} else if (type === 'decrease-session') {
(this.props.session_length > 1) ? this.props.decreaseSession() : isInvalid = true;
} else if (type === 'increase-break') {
this.props.increaseBreak();
} else if (type === 'decrease-break') {
(this.props.break_length > 1) ? this.props.decreaseBreak() : isInvalid = true;
}
if (isInvalid) {
alert("Times less than 1 minutes is not allowed.");
} else {
this.props.setTimer({
minutes: this.props.session_length,
seconds: 0,
percentage: this.getTimeElapsedPercentage(this.props.session_length, 0)
});
}
}
}
在上面的代码中,所有动作都是同步的,当我调用this.props.increaseSession()
时,它将调度增加会话的动作。然后,我在这个计时器对象接收session_length值的同时调用this.props.timer(timerObj)
,但是这个session_length值未更新意味着增加(如果我增加了会话)。
我的问题是所有动作都是同步的,那么为什么我在分发setTimer()
时收到旧值。任何解决此问题的建议将不胜感激。
如Roy所建议,如果在传递给setTimer之前自己更新值,则该百分比计算不正确。这是计算进度条(计时器周围的圆条)的函数。此功能负责在计时器启动时以及启动时和每秒设置值。尽管最初可以通过传递this.props.session_length
来正确计算百分比,但这不是正确的session_length。会话长度也在getTimeElapsedPercentage
内部使用,从而造成了问题。我可以使用一些逻辑来解决此问题,但我想拥有正确的解决方案而不是变通方法。
getTimeElapsedPercentage(minutes, seconds) {
let totalTimeInSec, timeElapsedInSec, timeRemainingInSec;
this.props.playType === 'break' ?
totalTimeInSec = this.props.break_length * 60 :
totalTimeInSec = this.props.session_length * 60;
timeRemainingInSec = minutes * 60 + seconds;
timeElapsedInSec = totalTimeInSec - timeRemainingInSec;
return timeElapsedInSec / totalTimeInSec * 100;
}
正如在评论中与Roy讨论的那样,我知道道具仅在每次渲染后才更新,因此当我使用this.props.session_length
设置计时器时,setTimer(timerObj)
给了我以前的值。
所以我进入了这个解决方案。在执行第一个操作后,我的商店已更新,但道具未更新,因此我从redux代码导入商店,并使用store.getState()
获取更新后的值。我在setTimer(timerObj)
和getTimeElapsedPercentage
中使用它来解决问题。
答案 0 :(得分:1)
我假设每次单击用于增加会话或中断的按钮时都会调用updateSettings(type)
。在这种情况下,当调用该函数并到达this.props.increaseSession()
或this.props.decreaseSession()
部分时,JavaScript引擎将调用这些函数,然后它将完成其工作。同时,编译器继续下一行并到达
if (isInvalid) {
alert("Times less than 1 minutes is not allowed.");
} else {
this.props.setTimer({
minutes: this.props.session_length,
seconds: 0,
percentage: this.getTimeElapsedPercentage(this.props.session_length, 0)
});
}
此时,增加或减少会话调用尚未完成,因此this.props.session_length
的值尚未更新。这就是为什么您看到计时器值始终落后于持续时间值的原因。
我的建议是将设置session_length
的代码从该函数移到用户单击开始时运行的函数。这样,您不必担心使两个变量保持同步。首先,让用户设置会话和中断长度。然后,当他们单击“开始”时,您将负责将这些值分配给计时器。
如果您不想这样,我建议将setTimer移至if,else语句中,并根据选择在调用以下代码时使用minutes: this.props.session_length + 1
或minutes: this.props.session_length - 1
。< / p>
this.props.setTimer({
minutes: this.props.session_length,
seconds: 0,
percentage: this.getTimeElapsedPercentage(this.props.session_length, 0)
});
更新:
要解决百分比问题,您可以更新getTimeElapsedPercentage
并接受一个名为plusMinus
的附加参数。然后根据增量或减量为+1或-1。进行较小的更改后,它的功能将如下所示。
getTimeElapsedPercentage(minutes, seconds, plusMinus) {
let totalTimeInSec, timeElapsedInSec, timeRemainingInSec;
this.props.playType === 'break' ?
totalTimeInSec = (this.props.break_length + plusMinus) * 60 :
totalTimeInSec = (this.props.session_length + plusMinus) * 60;
timeRemainingInSec = minutes * 60 + seconds;
timeElapsedInSec = totalTimeInSec - timeRemainingInSec;
return timeElapsedInSec / totalTimeInSec * 100;
}
在updateSettings中将其设置为if语句
let plusMinus = 0;
if (type === 'increase-session') {
plusMinus = 1;
} else if (type === 'decrease-session') {
plusMinus = -1;
}
然后致电如下
percentage: this.getTimeElapsedPercentage(this.props.session_length, 0, plusMinus)
我希望这对项目有帮助,并祝你好运。
答案 1 :(得分:1)
实际上,问题在于道具仅在渲染后才更新,而this.props.setTimer
在渲染前使用道具,因为道具具有旧的this.props.session_length
值。可以通过使用props更改时调用的react componentDidUpdate()
生命周期来解决此问题,然后可以设置计时器。
setTimer()
函数中删除updateSettings(type)
。因此道具仅更新一次(即在creaseSession,reducingSession等上)这负责在道具更改时设置计时器,这意味着现在它将更新的道具传递给计时器。
componentDidUpdate(prevProps) {
if (this.props.session_length !== prevProps.session_length) {
this.props.setTimer({
minutes: this.props.session_length,
seconds: 0,
percentage: this.getTimeElapsedPercentage(this.props.session_length, 0)
});
}
}