Redux 组件和计时器逻辑的 useEffect

时间:2021-01-13 17:33:41

标签: javascript reactjs redux react-redux react-hooks

所以,我有一个带有几个文本框(名称和计时器 i/p 框显示)和开始/停止按钮的功能组件。

我想要那个;

  1. 点击“开始”后,计时器框应计数并显示经过的秒数。
  2. 当单击停止时,名称和时间应保存到 redux 存储中,并且计时器 i/p 框应归零。 (名称/计时器的保存值作为另一个组件的一部分显示在下方)
  3. 当焦点在计时器框上时,计时器应停止/暂停
  4. 当我们从计时器框中聚焦/模糊时,计时器应从该点恢复。

我已在以下链接中将我的代码添加到沙箱中。 https://codesandbox.io/s/crisil-tp7pv?file=/src/TestComponent.js

部分相关代码也在下方突出显示。本质上,我想了解,如果我通过使用 useEffect 来更新计时器框是正确的吗? 有什么改进方法的建议吗?

export const TestComponent = (props) => {
  const [task, setTask] = useState({ id: 0, taskName: "", timeField: 0 });
  const [stopTimerEvt, setStopTimerEvt] = useState(true);
  //var timerId;

  useEffect(() => {
    var seconds = 0;
    var interval;
    if (stopTimerEvt === false) {
      interval = setInterval(function () {
        setTask((prevState) => {
          return { ...prevState, timeField: seconds++ };
        });
      }, 1000);
    }
    return () => clearInterval(interval);
  }, [stopTimerEvt]);

  const startTimer = () => {
    setStopTimerEvt(false);
    /*
    timerId = setInterval(function () {
      setTask((prevState) => {
        return { ...prevState, timeField: seconds++ };
      });
    }, 1000);
    */
  };

  const stopTimer = () => {
    //clearInterval(timerId);
    setStopTimerEvt(true);
    props.saveTask(task);
    setTask((prevState) => {
      return { ...prevState, timeField: 0 };
    });
  };

  const handleChange = (e) => {
    setTask((prevState) => ({
      ...prevState,
      [e.target.id]: e.target.value
    }));
  };

  return (
    <main>
      <input
        type="text"
        id="taskName"
        value={task.taskName}
        onChange={handleChange}
      />
      <input
        type="number"
        id="timeField"
        value={task.timeField}
        onChange={handleChange}
      />
      <button id="start" onClick={startTimer}>
        Start
      </button>
      <button id="stop" onClick={stopTimer}>
        Stop
      </button>
    </main>
  );
};

export default connect(null, { saveTask })(TestComponent);

1 个答案:

答案 0 :(得分:1)

以下是您需要在 TestComponent 中进行的一些更改:

export const TestComponentNew = (props) => {
  const [task, setTask] = useState({ taskName: "", timeField: 0 });
  const timer = useRef();

  useEffect(() => {
    return () => stopTimer();
  }, []);

  const startTimer = () => {
    timer.current = setInterval(function () {
      setTask((v) => ({ ...v, timeField: +v.timeField + 1 }));
    }, 1000);
  };

  const stopTimer = () => {
    clearInterval(timer.current);
    timer.current = null;
    props.saveTask(task);
    setTask({ taskName: "", timeField: 0 });
  };

  const handleChange = (e) => {
    setTask((prevState) => ({
      ...prevState,
      [e.target.id]: e.target.value
    }));
  };

  return (
    <main>
      <input
        type="text"
        id="taskName"
        value={task.taskName}
        onChange={handleChange}
        placeholder="task name"
      />
      <input
        type="number"
        id="timeField"
        value={task.timeField}
        onChange={handleChange}
      />
      <button id="start" onClick={startTimer}>
        Start
      </button>
      <button id="stop" onClick={stopTimer}>
        Stop
      </button>
    </main>
  );
};

这是演示:https://codesandbox.io/s/crisil-forked-pfrb3?file=/src/TestComponentNew.js

EDITED

export const TestComponentNew = (props) => {
  const [task, setTask] = useState({ taskName: "", timeField: 0 });
  const timer = useRef();

  useEffect(() => {
    return () => stopTimer();
  }, []);

  const startTimer = () => {
    timer.current = setInterval(function () {
      setTask((v) => ({ ...v, timeField: +v.timeField + 1 }));
    }, 1000);
  };

  const stopTimer = () => {
    clearInterval(timer.current);
    timer.current = null;
    props.saveTask(task);
    setTask({ taskName: "", timeField: 0 });
  };

  const handleChange = (e) => {
    setTask((prevState) => ({
      ...prevState,
      [e.target.id]: e.target.value
    }));
  };

  const handlePause = () => {
    clearInterval(timer.current);
  };

  return (
    <main>
      <input
        type="text"
        id="taskName"
        value={task.taskName}
        onChange={handleChange}
        placeholder="task name"
      />
      <input
        type="number"
        id="timeField"
        value={task.timeField}
        onChange={handleChange}
        onFocus={handlePause}
        onBlur={startTimer}
      />
      <button id="start" onClick={startTimer}>
        Start
      </button>
      <button id="stop" onClick={stopTimer}>
        Stop
      </button>
    </main>
  );
};