挂钩中 1 分钟计数器的重置无法正常工作

Reset of 1 minute counter in hooks isn't working properly

我正在创建 1 分钟计数器并且它正在工作,但是当我单击重置按钮重新启动同一个计数器时,出现了奇怪的行为。

这是代码

export default function App() {
  const [counter, setCounter] = useState(60);
  useEffect(() => {
    counter > 0 && setTimeout(() => setCounter(counter - 1), 1000);
  }, [counter]);
  const handleReset = () => {
    setCounter(60);
  }
  return (
    <div className="App">
      <h1>Counter</h1>
      <p>{counter}</p>
      <button onClick={handleReset}>Reset</button>
    </div>
  );
}

Code in Sandbox

有人可以帮我改进一下吗?谢谢

考虑让 useEffect 具有一个空的依赖项数组和一个间隔而不是超时。然后,在超时回调中,如果 counter 大于 0,则递减:

const App = () => {
  const [counter, setCounter] = React.useState(60);
  React.useEffect(() => {
    setInterval(() => {
      // Must use callback form here; outer `counter` is in stale closure
      setCounter(counter => counter === 0 ? counter : counter - 1);
    }, 1000);
  }, []);
  const handleReset = () => {
    setCounter(60);
  }
  return (
    <div className="App">
      <h1>Counter</h1>
      <p>{counter}</p>
      <button onClick={handleReset}>Reset</button>
    </div>
  );
}
ReactDOM.render(<App />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div class="react"></div>

您当前使用 [counter] 依赖数组的实现意味着每次 counter 更改时都会设置新的递归超时,这是不可取的;您将同时获得多个递归超时 运行。

如果我理解正确的话,问题是在每次更新时都会创建一个新的 setTimeout,并且所有创建的超时都会同时更新计数器。不要使用 setTimeout,而是尝试使用 setInterval,您可以在挂钩生命结束时清理它。

useEffect(() => {
  let interval = setInterval(
    () => setCounter(counter > 0 ? counter - 1 : counter),
    1000
  );
  return () => clearInterval(interval);
}, [counter]);