useFps()
Last updated: 24/04/2026
Overview
useFps runs a requestAnimationFrame loop and estimates how many frames ran in a sliding window of sampleMs milliseconds (default 1000). Each time the elapsed time since the window start reaches sampleMs, it sets FPS to frames × 1000 / elapsed (rounded) and starts counting the next window. Smaller sampleMs makes the readout more responsive (noisier); larger values average over a longer period. The value is 0 until the first full window completes. The hook is meant for on-screen diagnostics, not for precise performance profiling. Changing sampleMs re-runs the effect and resets the internal counters.
What it accepts
sampleMs(optional, default1000) - width of each averaging window in ms.
What it returns
- A
number: estimated frames per second.
Usage
Show two readouts: default 1s smoothing vs a faster 0.5s window.
import useFps from '@dedalik/use-react/useFps'
function Example() {
const fpsSmooth = useFps(1000)
const fpsFast = useFps(500)
return (
<dl>
<dt>Estimated FPS (sample 1000 ms, default)</dt>
<dd>
<strong>{fpsSmooth}</strong>
</dd>
<dt>Estimated FPS (sample 500 ms)</dt>
<dd>
<strong>{fpsFast}</strong>
</dd>
</dl>
)
}
export default function Demo() {
return <Example />
}API Reference
useFps
Signature: useFps(sampleMs = 1000): number
Parameters
sampleMs(optional) - Averaging window in milliseconds. Default 1000.
Returns
A number: current FPS estimate from the rAF-based counter.
Copy-paste hook
TypeScript
import { useEffect, useRef, useState } from 'react'
/**
* Estimates current frames-per-second using requestAnimationFrame.
*/
export default function useFps(sampleMs = 1000): number {
const [fps, setFps] = useState(0)
const framesRef = useRef(0)
const startRef = useRef(0)
const rafRef = useRef<number | null>(null)
useEffect(() => {
if (typeof window === 'undefined') return
const loop = (ts: number) => {
if (startRef.current === 0) startRef.current = ts
framesRef.current += 1
const elapsed = ts - startRef.current
if (elapsed >= sampleMs) {
setFps(Math.round((framesRef.current * 1000) / elapsed))
framesRef.current = 0
startRef.current = ts
}
rafRef.current = window.requestAnimationFrame(loop)
}
rafRef.current = window.requestAnimationFrame(loop)
return () => {
if (rafRef.current != null) window.cancelAnimationFrame(rafRef.current)
}
}, [sampleMs])
return fps
}JavaScript
import { useEffect, useRef, useState } from 'react'
/**
* Estimates current frames-per-second using requestAnimationFrame.
*/
export default function useFps(sampleMs = 1000) {
const [fps, setFps] = useState(0)
const framesRef = useRef(0)
const startRef = useRef(0)
const rafRef = useRef(null)
useEffect(() => {
if (typeof window === 'undefined') return
const loop = (ts) => {
if (startRef.current === 0) startRef.current = ts
framesRef.current += 1
const elapsed = ts - startRef.current
if (elapsed >= sampleMs) {
setFps(Math.round((framesRef.current * 1000) / elapsed))
framesRef.current = 0
startRef.current = ts
}
rafRef.current = window.requestAnimationFrame(loop)
}
rafRef.current = window.requestAnimationFrame(loop)
return () => {
if (rafRef.current != null) window.cancelAnimationFrame(rafRef.current)
}
}, [sampleMs])
return fps
}