useInterval()

Use setInterval in functional React component with the same API. Set your callback function as a first parameter and a delay (in milliseconds) for the second argument. You can also stop the timer passing null instead the delay.

The main difference between the setInterval you know and this useInterval hook is that its arguments are "dynamic". You can get more information in the Dan Abramov's blog post.

The Hook

1import { useEffect, useRef } from 'react'
2
3function useInterval(callback: () => void, delay: number | null) {
4 const savedCallback = useRef(callback)
5
6 // Remember the latest callback if it changes.
7 useEffect(() => {
8 savedCallback.current = callback
9 }, [callback])
10
11 // Set up the interval.
12 useEffect(() => {
13 // Don't schedule if no delay is specified.
14 if (delay === null) {
15 return
16 }
17
18 const id = setInterval(() => savedCallback.current(), delay)
19
20 return () => clearInterval(id)
21 }, [delay])
22}
23
24export default useInterval

Usage

1import React, { ChangeEvent, useState } from 'react'
2
3import useInterval from './useInterval'
4
5export default function Component() {
6 // The counter
7 const [count, setCount] = useState<number>(0)
8 // Dynamic delay
9 const [delay, setDelay] = useState<number>(1000)
10 // ON/OFF
11 const [isPlaying, setPlaying] = useState<boolean>(false)
12
13 useInterval(
14 () => {
15 // Your custom logic here
16 setCount(count + 1)
17 },
18 // Delay in milliseconds or null to stop it
19 isPlaying ? delay : null,
20 )
21
22 const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
23 setDelay(Number(event.target.value))
24 }
25
26 return (
27 <>
28 <h1>{count}</h1>
29 <button onClick={() => setPlaying(!isPlaying)}>
30 {isPlaying ? 'pause' : 'play'}
31 </button>
32 <p>
33 <label>Delay: </label>
34 <input type="number" onChange={handleChange} value={delay} />
35 </p>
36 </>
37 )
38}

See a way to make this page better?
Edit there »