Search code examples
javascriptreactjsreact-hookscountdown

How make react countdown timer


i'm trying to do countdown timer with react. It will be basically countdown from 10 to 0 and when 0 i will call some function.

i found ideally for me some example: https://codesandbox.io/s/0q453m77nw?from-embed but it's a class component i wan't to do that with functional component and hooks but i can't.

i tried:

function App() {
  const [seconds, setSeconds] = useState(10);
  useEffect(() => {
    setSeconds(setInterval(seconds, 1000));
  }, []);

  useEffect(() => {
    tick();
  });

  function tick() {
    if (seconds > 0) {
      setSeconds(seconds - 1)
    } else {
      clearInterval(seconds);
    }
  }

  return (

    <div className="App">
      <div
        {seconds}
      </div>
    </div>
  );
}

export default App;

it's count down from 10 to 0 very quickly not in 10 seconds. where i mistake ?


Solution

  • It appears the multiple useEffect hooks are causing the countdown to run more than once per second.

    Here's a simplified solution, where we check the seconds in the useEffect hook and either:

    • Use setTimeout to update seconds after 1 second, or
    • Do something else (the function you want to call at the end of the countdown)

    There are some downsides to this method, see below.

    function App() {
      const [seconds, setSeconds] = React.useState(10);
    
      React.useEffect(() => {
        if (seconds > 0) {
          setTimeout(() => setSeconds(seconds - 1), 1000);
        } else {
          setSeconds('BOOOOM!');
        }
      });
    
      return (
        <div className="App">
          <div>
            {seconds}
          </div>
        </div>
      );
    }
    
    ReactDOM.render(<App />, document.getElementById('root'))
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script>
    
    <div id="root"></div>

    Downsides

    Using setInterval has the downside that it could be stopped - for example, the component is unmounted, you navigate to a different tab, or close your computer. If the timer requires more robustness, the better alternative would be to store an endTime in the state (like a global store or context) and have your component check the current time against the endTime to calculate the countdown.