首页 > 解决方案 > 当我重置状态时,进度条重新呈现以前的状态

问题描述

我有一个进度条接收一个值作为宽度当我单击“重置”按钮时,它会将状态重置为 0 并按预期工作但是当我在进度条为 100% 宽度之前单击重置按钮时,它将继续增加状态

我怎样才能防止这种情况发生?

import React, { useEffect, useState } from "react";

function ProgressBar({ value = 0 }) {
  const [percent, setPercent] = useState(value);
  useEffect(() => {
    setPercent(value);
  }, [value]);
  return (
    <>
      {value.toFixed(2)}%
      <div
        style={{ display: "flex", width: "100%", border: "1px solid black" }}
      >
        <div
          style={{
            border: "1px solid black",
            backgroundColor: "red",
            height: "0.5rem",
            transition: 0,
            width: `${percent}%`
          }}
        ></div>
      </div>
    </>
  );
}

export default function App() {
  const [percent, setPercent] = useState(0);
  const [willReset, setWillReset] = useState(false);

  const step = 100 / 3;

  useEffect(() => {
    function updateProgress() {
      if (!willReset) {
        setTimeout(() => {
          if (percent + step > 100) {
            setPercent(percent + (100 - percent));
          } else {
            setPercent(percent + step);
          }
        }, 1000);
      } else {
        setPercent(0);
      }
    }
    updateProgress();
  }, [percent, willReset]);

  return (
    <div className="App">
      <button
        onClick={() => {
          setWillReset(true);
        }}
      >
        Reset
      </button>
      {percent !== 100 && <ProgressBar value={percent} />}
    </div>
  );
}

标签: javascriptreactjsreact-hooks

解决方案


发生这种情况的原因是因为您在钩子setTimeout内部使用。useEffect你必须从你的useEffect回调中返回一个清理函数来清除setTimeout它,否则它将继续被调用。

我会这样写:

useEffect(() => {
  if (willReset) {
    setPercent(0);
    return;
  }

  const id = setTimeout(() => {
    if (percent + step > 100) {
      setPercent(percent + (100 - percent));
    } else {
      setPercent(percent + step);
    }
  }, 1000);

  return () => clearTimeout(id);
}, [percent, willReset]);

推荐阅读