首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么React没有实时更新状态和显示?

为什么React没有实时更新状态和显示?
EN

Stack Overflow用户
提问于 2021-02-05 13:22:55
回答 1查看 76关注 0票数 0

我无法让我的react项目实时更新"timeRemaining“状态。我知道它是异步运行的,但我不知道如何解决这个问题。除了"timeRemaining“更新之外,该项目正常工作。例如,它呈现:(开始于: 25:00) click=> (应该是: 20:00,实际上是: 25:00) click=> (应该是: 15:00,实际上是: 20:00)...以此类推。我该如何处理这种延迟?

"timeRemaining“状态由"handleFocusTimeAdd/sub”和"handleBreakTimeAdd/Sub“函数更新,并由"infoComponent”显示。

下面是完整的代码:

代码语言:javascript
复制
import React, { useState } from "react";
import classNames from "../utils/class-names";
import useInterval from "../utils/useInterval";
import { minutesToDuration, secondsToDuration } from "../utils/duration";

function Pomodoro() {
  // Timer starts out paused
  const [isTimerRunning, setIsTimerRunning] = useState(false);
  const [focusDuration, setFocusDuration] = useState(1500);
  const [breakDuration, setBreakDuration] = useState(300);
  const [timeRemaining, setTimeRemaining] = useState(focusDuration);
  const [onBreak, setOnBreak] = useState(false);
  const [showInfo, setShowInfo] = useState(false);

  // Update every second if timer is running
  useInterval(
    () => {
      setTimeRemaining((timeRemaining) => timeRemaining - 1);
      play();
    },
    isTimerRunning ? 1000 : null
  );

  // Handle the PLAY button
  function playPause() {
    setIsTimerRunning((prevState) => !prevState);
    setShowInfo(true);
  }

  // Handle PLAY
  function play() {
    if (timeRemaining === 0) {
      if (onBreak) {
        setTimeRemaining((timeRemaining) => timeRemaining + focusDuration);
        setOnBreak(false);
      }
      if (!onBreak) {
        setTimeRemaining((timeRemaining) => timeRemaining + breakDuration);
        setOnBreak(true);
      }
    }
  }

  // Handle the STOP button
  const handleStopBtn = () => {
    setIsTimerRunning(false);
    setFocusDuration(1500);
    setBreakDuration(300);
    setTimeRemaining(1500);
    setShowInfo(false);
  };

  // Handle the focus duration view SUBTRACT
  const handleFocusTimeSub = (focusDuration) => {
    if (focusDuration > 300) {
      setFocusDuration((focusDuration) => focusDuration - 300);
    } else {
      setFocusDuration((focusDuration) => focusDuration);
    }
    setTimeRemaining(focusDuration)
    return focusDuration;
  };

  // Handle the focus duration view ADD
  const handleFocusTimeAdd = (focusDuration) => {
    if (focusDuration < 3600) {
      setFocusDuration((focusDuration) => focusDuration + 300);
    } else {
      setFocusDuration((focusDuration) => focusDuration);
    }
    setTimeRemaining(focusDuration)
    return focusDuration;
  };

  // Handle the break duration view SUBTRACT
  const handleBreakTimeSub = (breakDuration) => {
    if (breakDuration > 60) {
      setBreakDuration((breakDuration) => breakDuration - 60);
    } else {
      setBreakDuration((breakDuration) => breakDuration);
    }
    return breakDuration;
  };

  // Handle the break duration view ADD
  const handleBreakTimeAdd = (breakDuration) => {
    if (breakDuration < 900) {
      setBreakDuration((breakDuration) => breakDuration + 60);
    } else {
      setBreakDuration((breakDuration) => breakDuration);
    }
    return breakDuration;
  };

  const infoComponent = () => {
    if (showInfo) {
      if (onBreak) {
        return (
          <div>
            <div className="row mb-2">
              <div className="col">
                <h2 data-testid="session-title">
                  On Break for {secondsToDuration(breakDuration)} minutes
                </h2>
                <p className="lead" data-testid="session-sub-title">
                  {secondsToDuration(timeRemaining)} remaining
                </p>
              </div>
            </div>
            <div className="row mb-2">
              <div className="col">
                <div className="progress" style={{ height: "20px" }}>
                  <div
                    className="progress-bar"
                    role="progressbar"
                    aria-valuemin="0"
                    aria-valuemax="100"
                    aria-valuenow="0" // TODO: Increase aria-valuenow as elapsed time increases
                    style={{ width: "0%" }} // TODO: Increase width % as elapsed time increases
                  />
                </div>
              </div>
            </div>
          </div>
        );
      }
      if (!onBreak) {
        return (
          <div>
            <div className="row mb-2">
              <div className="col">
                <h2 data-testid="session-title">
                  Focusing for {secondsToDuration(focusDuration)} minutes
                </h2>
                <p className="lead" data-testid="session-sub-title">
                  {secondsToDuration(timeRemaining)} remaining
                </p>
              </div>
            </div>
            <div className="row mb-2">
              <div className="col">
                <div className="progress" style={{ height: "20px" }}>
                  <div
                    className="progress-bar"
                    role="progressbar"
                    aria-valuemin="0"
                    aria-valuemax="100"
                    aria-valuenow="0" // TODO: Increase aria-valuenow as elapsed time increases
                    style={{ width: "0%" }} // TODO: Increase width % as elapsed time increases
                  />
                </div>
              </div>
            </div>
          </div>
        );
      }
    }
    return null;
  };

  return (
    <div className="pomodoro">
      <div className="row">
        <div className="col">
          <div className="input-group input-group-lg mb-2">
            <span className="input-group-text" data-testid="duration-focus">
              Focus Duration: {secondsToDuration(focusDuration)}
            </span>
            <div className="input-group-append">
              <button
                onClick={() => handleFocusTimeSub(focusDuration)}
                type="button"
                className="btn btn-secondary"
                data-testid="decrease-focus"
              >
                <span className="oi oi-minus" />
              </button>

              <button
                onClick={() => {
                  handleFocusTimeAdd(focusDuration);
                }}
                type="button"
                className="btn btn-secondary"
                data-testid="increase-focus"
              >
                <span className="oi oi-plus" />
              </button>
            </div>
          </div>
        </div>
        <div className="col">
          <div className="float-right">
            <div className="input-group input-group-lg mb-2">
              <span className="input-group-text" data-testid="duration-break">
                Break Duration: {secondsToDuration(breakDuration)}
              </span>
              <div className="input-group-append">
                <button
                  onClick={() => handleBreakTimeSub(breakDuration)}
                  type="button"
                  className="btn btn-secondary"
                  data-testid="decrease-break"
                >
                  <span className="oi oi-minus" />
                </button>
                <button
                  onClick={() => handleBreakTimeAdd(breakDuration)}
                  type="button"
                  className="btn btn-secondary"
                  data-testid="increase-break"
                >
                  <span className="oi oi-plus" />
                </button>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div className="row">
        <div className="col">
          <div
            className="btn-group btn-group-lg mb-2"
            role="group"
            aria-label="Timer controls"
          >
            <button
              type="button"
              className="btn btn-primary"
              data-testid="play-pause"
              title="Start or pause timer"
              onClick={playPause}
            >
              <span
                className={classNames({
                  oi: true,
                  "oi-media-play": !isTimerRunning,
                  "oi-media-pause": isTimerRunning,
                })}
              />
            </button>
            <button
              onClick={handleStopBtn}
              type="button"
              className="btn btn-secondary"
              title="Stop the session"
            >
              <span className="oi oi-media-stop" />
            </button>
          </div>
        </div>
      </div>
      <div>{infoComponent()}</div>
    </div>
  );
}

export default Pomodoro;

谢谢你的帮助!我是个新手,还在努力解决问题。

EN

回答 1

Stack Overflow用户

发布于 2021-02-07 17:41:18

看起来你在回调中访问了一个错误的值引用。我将重命名handleFocusTimeSub回调中的变量以暴露错误。

代码语言:javascript
复制
const handleFocusTimeSub = (inputFocusDuration) => {
  if (inputFocusDuration > 300) {
    setFocusDuration((stateFocusDuration) => stateFocusDuration - 300);
  } else {
    setFocusDuration((stateFocusDuration) => stateFocusDuration);
  }
  setTimeRemaining(inputFocusDuration);
  return inputFocusDuration;
};

您可能打算将focusDuration的新状态传递给setTimeRemaining

代码语言:javascript
复制
const handleFocusTimeSub = (inputFocusDuration) => {
  if (inputFocusDuration > 300) {
    setFocusDuration(
      (stateFocusDuration) => (
        setTimeRemaining(stateFocusDuration - 300),
        stateFocusDuration - 300
      )
    );
  } else {
    setFocusDuration(
      (stateFocusDuration) => (
        setTimeRemaining(stateFocusDuration),
        stateFocusDuration
      )
    );
  }
  return inputFocusDuration;
};

handleFocusTimeAdd也有同样的bug,修复方法也是一样的。

我向您展示的修复是使其正常工作的最小更改。为了避免将来出现这种类型的bug,您需要将需要相互了解的状态变量保存在一个共享的缩减程序中,而不是单独的状态挂钩中。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66057964

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档