Search code examples
reactjsreact-hooksuse-effect

Increase the counter, then reset it when a certain limit is reached


I just started learning react and I have about a performance question. I want to increment a counter using the setInterval function and then reset it when the length of the array is reached. The problem is I need to add an active variable for the useEffect dependency, which removes the interval and then creates it again.

useEffect(() => {
     const timer = setInterval(() => {
        active == arr.length - 1 ? setActive(0) : setActive((active) => active + 1)
     }, 3000)
     return () => clearInterval(timer)
}, [active])

So, I wrote code like this, which looks crazy, but does the same job without removing the interval, and gets the actual version of the active variable from the callback.

useEffect(() => {
     const timer = setInterval(() => {
        setActive((active) => (active === arr.length - 1 ? active == 0 : active + 1))
     }, 3000)
     return () => clearInterval(timer)
}, [])

The question is how best to write and not do unnecessary work in the component


Solution

  • I would probably split all this logic out into a couple effects.

    One to manage incrementing active on the interval and clearing the interval when the component unmounts.

    useEffect(() => {
      const timer = setInterval(() => {
        setActive(active => active + 1);
      }, 3000);
    
      return () => clearInterval(timer);
    }, []);
    

    A second to reset the state on the condition.

    useEffect(() => {
      if (active === arr.length - 1) {
        setActive(0);
      }
    }, [active, arr]);
    

    I would also caution you to protect against the edge case where active is updated to 0 and the arr array is an array of length 1 as this will trigger render looping.