Kay
Kay

Reputation: 881

SetInterval causes too many re-renders React

Hello I would like to put setInterval in my React project to add 1 for each second but I got an error like in title of this post. js:

const [activeTab, setActiveTab] = useState(0)
useEffect(() => {
       setInterval(setActiveTab(prevTab => {
           if (prevTab === 3) return 0
           console.log('hi')
           return prevTab += 1
               
       }), 1000)
   
   })

Upvotes: 1

Views: 2623

Answers (2)

Ahmad Raza
Ahmad Raza

Reputation: 91

  useEffect(() => {
    setInterval(() => {
      setActiveTab((prevTab) => {
        if (prevTab !== 3) {
          return (prevTab += 1);
        } else {
          return 0;
        } // console.log("hi");
      });
    }, 1000);
  }, []);

Upvotes: 0

T.J. Crowder
T.J. Crowder

Reputation: 1074148

There are a few issues:

  1. You're not passing a function to setInterval, you're calling setActiveTab and passing its return value into setInterval.

  2. If you were passing in a function, you'd be adding a new repeated timer every time your componennt ran. See the documentation — useEffect:

    By default, effects run after every completed render...

    And setInterval:

    The setInterval() method... repeatedly calls a function or executes a code snippet, with a fixed time delay between each call.

    (my emphasis)

    Starting a new repeating timer every time your component re-renders creates a lot of repeating timers.

  3. Your component will leave the interval timer running if the component is unmounted. It should stop the interval timer.

To fix it, pass in a function, add a dependency array, and add a cleanup callback to stop the interval:

const [activeTab, setActiveTab] = useState(0);
useEffect(() => {
    const handle = setInterval(() => { // *** A function
        setActiveTab(prevTab => {
            if (prevTab === 3) return 0;
            console.log("?ghi");
            return prevTab += 1;
        });
    }, 1000);
    return () => {              // *** Clear the interval on unmount
        clearInterval(handle);  // ***
    };                          // ***
}, []); // *** Empty dependency array = only run on mount

Side note: Assuming you don't need the console.log, that state setter callback function can be simpler by using the remainder operator:

setActiveTab(prevTab => (prevTab + 1) % 3);

Upvotes: 6

Related Questions