Hoppa till huvudinnehåll

Custom hook: useInterval

· 2 min att läsa
Filip Tammergård
Programmerare på Frilans Finans

setInterval är en funktion i JavaScript som kan användas för att lösa alla typer av saker som ska uppdateras eller hända i ett givet intervall. Jag har använt setInterval flera gånger på den här bloggen, bland annat i inläggen Födelsedagsmatematik och Bokstavsspel.

Att använda setInterval kan ibland vara lite bökigt. Man måste komma ihåg att köra clearInterval för att inte introducera minnesläckor, till exempel.

Jag bestämde mig för att göra en custom hook som förenklar användningen. Här är resultatet:

import { useEffect } from "react"

export const useInterval = (callback: () => void, delay: number | null) => {
useEffect(() => {
if (delay !== null) {
const id = setInterval(callback, delay)
return () => clearInterval(id)
}
}, [callback, delay])
}

Så här enkelt är det att använda hooken:

useInterval(() => {
console.log("Där gick en sekund!")
}, 1000)

Syntaxen är identisk med setInterval, vilket gör den intuitiv och enkel att använda. Men det löser minneshanteringen åt dig.

Hooken kommer ännu mer väl till pass när det finns ett behov av att kunna styra intervalltiden dynamiskt och pausa intervallet.

const [isRunning, setIsRunning] = useState(false)
const [delay, setDelay] = useState(500)
const [count, setCount] = useState(0)

useInterval(
() => {
setCount((prev) => prev + 1)
},
isRunning ? delay : null,
)

Här är isRunning en variabel i state som initialt är false men kan ändras till true för att starta intervallet. Och intervalltiden kan ändras efter behov.

Låt oss säga att vi vill ha en räknare som tickar upp i en valbar hastighet och som automatiskt pausar när hastigheten blir för hög (i det här fallet 50 ms). Så här:

0

Testa att ändra delay till 50 och sedan till 49 så ser du att räknaren stannar. Den nollställs inte, så om man ändrar tillbaka till 50 igen kommer räknaren fortsätta från där den var. Funktionaliteten kan åstadkommas så här:

import { useInterval } from "hooks/useInterval"
import { useEffect, useState } from "react"

const Counter = () => {
const [isRunning, setIsRunning] = useState(false)
const [delay, setDelay] = useState(500)
const [count, setCount] = useState(0)

useInterval(
() => {
setCount((prev) => prev + 1)
},
isRunning ? delay : null,
)

useEffect(() => {
if (delay < 50) {
setIsRunning(false)
} else {
setIsRunning(true)
}
}, [delay])

const handleDelayChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const input = parseInt(e.target.value, 10)
setDelay(input)
}

return (
<div>
<span>Choose delay [ms]...</span>
<br />
<input type="number" onChange={handleDelayChange} value={delay} />
<p>{count}</p>
</div>
)
}

export default Counter

Supersmidigt att använda jämfört med den vanliga setInterval-funktionen i varje implementation.