Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React setInterval and useState

I have 2 question. First, why this code does not work. Second, why this code slow when it comes 2^n -1 for example 1-3-7-15

let time = 0
function App() {
  const [mytime, setMytime] = useState(time)
  setInterval(() => {
    time += 1
    setMytime(time)
  }, 1000)
  return <div> {mytime} </div>
like image 650
PYigit Avatar asked Jun 06 '26 22:06

PYigit


2 Answers

Issue

The setInterval gets called each time when mytime changes for rerendering (when you call the setMytime). And the number of setInterval calls grows exponentially. This would lead to a memory leak as well.

Solution

You should run it only once. You should use useEffect hook with an empty dependency array.

Try like this.

import { useEffect, useState } from "react";

function App() {
  const [mytime, setMytime] = useState(0);

  useEffect(() => {
    // create a interval and get the id
    const myInterval = setInterval(() => {
      setMytime((prevTime) => prevTime + 1);
    }, 1000);
    // clear out the interval using the id when unmounting the component
    return () => clearInterval(myInterval);
  }, []);

  return <div> {mytime} </div>;
}

export default App;

Edit competent-night-ufndlc

like image 120
Amila Senadheera Avatar answered Jun 09 '26 10:06

Amila Senadheera


To extend @Amila's answer,

What if you want to start, stop, reset timer using functions ?
  1. Make sure you use useRef(), because useState() will cause render.
  2. Make sure you unmount the interval in the useState() as it will cause skipping of timer.
    useEffect(() => {
         return () => clearInterval(currentTimer.current);
     }, []);
    

Use the following code:

    const [time, setTime] = useState(0);
    const currentTimer = useRef();
    useEffect(() => {
        return () => clearInterval(currentTimer.current);
    }, []);
    const startTimer = () => {
        currentTimer.current = setInterval(() => {
            setTime((prev) => prev + 1);
            console.log(time);
        }, 1000);
    };
    const stopTimer = () => {
        clearInterval(currentTimer.current);
    };
    const resetTimer = () => {
        clearInterval(currentTimer.current);
        setTime(0);
    };
    return (
        <div>
            <div>{time}</div>
            <button onClick={startTimer}>Start</button>
            <button onClick={stopTimer}>Stop</button>
            <button onClick={resetTimer}>Reset</button>
        </div>
    );
like image 20
krishnaacharyaa Avatar answered Jun 09 '26 10:06

krishnaacharyaa