> ## Content Index
> Fetch the complete content index at: https://reactpractice.dev/llms.txt
> Use this file to discover other available public pages before exploring further.

# Why you shouldn't save the interval id in the state
- URL: https://reactpractice.dev/articles/why-you-shouldnt-save-the-interval-id-in-the-state/
- Published: 2024-11-07T07:48:16.000Z
- Updated: 2026-06-01T01:56:52.000Z
- Author: Corina Udrescu
- Tags: Articles, #corina-2, Working with setInterval, #Import 2026-06-09 12:07

When working with intervals, it's important to also clear them. 

You can achieve this by passing the interval id you received when starting the interval to the `clearInterval` function:

```
// start an interval and get its id
const intervalId = setInterval(() => console.log('hello'), 1000);
// clear the interval
clearInterval(intervalId);
```

When using intervals inside a React component, you'd want to save a reference to the interval id so you can later clear it. And it's tempting to just pop it into a state variable:

```
 // store interval id in state
  const [intervalId, setIntervalId] = useState<number | null>(null);

  const handleClickStart = () => {
    const intervalId = window.setInterval(() => {
        // ...
    }, 1000);

    setIntervalId(intervalId);
  };

  const handleClickStop = () => {
    // If the timer is already stopped, do nothing
    if (intervalId === null) {
      return;
    }

    clearInterval(intervalId);
    setIntervalId(null);
  };
```

But there's a problem with this approach - the state should be used for things that cause the UI to update: but saving the interval id is not something that needs to refresh the UI, does it?

When you save the id in the state, every time you call `setIntervalId`, you trigger an unnecesarry rerender. Also, when you would clear the interval on unmount, unless you add it as a dependency, you'd have access to the "old" value of the interval id, due to a "stale closure":

```
  useEffect(() => {
    return () => {
      clearInterval(intervalId)
    };
  }, [intervalId]);
```

A better approach is using a [ref](https://reactjs.org/docs/hooks-reference.html?ref=reactpractice.dev#useref) to store the interval id. This way, we can still keep a reference to the id of the currently running timer, but we no longer cause unnecessary renders and we have access to the latest variable when clearing the interval on unmount.

```
 // store interval id as ref
  const intervalId = useRef<number | null>(null);

  const handleClickStart = () => {
    // update current value of the ref
    // does not trigger a rerender
    intervalId.current = window.setInterval(() => {
        // ...
    }, 1000);
  };

  const handleClickStop = () => {
    // If the timer is already stopped, do nothing
    if (intervalId.current === null) {
      return;
    }

    clearInterval(intervalId.current);
    // clear current value of the ref
    // does not trigger a rerender
    intervalId.current = null;
  };

  // Cleanup the timer on unmount
  useEffect(() => {
    return () => {
      clearInterval(intervalId.current)
    };
  }, []);
```

Want to check your understanding of working with intervals in React?   
Check out these challenges:  
 \- [Create a timer that can be started and stopped](https://reactpractice.dev/exercise/create-a-timer-that-can-be-started-and-stopped/)  
 \- [Build a Typewriter effect component](https://reactpractice.dev/exercise/build-a-typewriter-effect-component/)