在react-redux

时间:2018-08-12 07:43:16

标签: reactjs redux

我正在尝试将pomodoro clock作为FreeCodeCamp的练习项目。这是一个简单的时钟,每当当前计时器结束时,它就会在会话时间和休息时间之间切换。

我正在面对与redux反应有关的问题。这是我的应用程序启动时的状态。

Initial State

当我单击减号或加号时,存储中的计时器和会话/中断时间将相应更新,但这没有发生。会话/中断长度已更新,但计时器反映了先前的值。这是反映我增加会话时问题的屏幕截图

Increase Session

这是我的代码,对此负责

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中使用它来解决问题。

2 个答案:

答案 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 + 1minutes: 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)
            });
        }
    }