useThrottle Hook
December 21, 2025
Throttling is similar to debouncing, but instead of waiting for a pause, it ensures a function is called at most once per specified time period. This is useful for events that fire frequently, like scroll or resize.
import { useEffect, useRef, useState } from 'react';
export function useThrottle<T>(value: T, delay: number): T {
const [throttledValue, setThrottledValue] = useState(value);
const lastRan = useRef(Date.now());
useEffect(() => {
const handler = setTimeout(() => {
if (Date.now() - lastRan.current >= delay) {
setThrottledValue(value);
lastRan.current = Date.now();
}
}, delay - (Date.now() - lastRan.current));
return () => clearTimeout(handler);
}, [value, delay]);
return throttledValue;
}
How It Works
lastRantracks the last time the value was updated.- The function only updates if enough time has passed since the last update.
- Unlike debounce, throttling guarantees execution at regular intervals.
Example Usage
function ScrollComponent() {
const [scrollY, setScrollY] = useState(0);
const throttledScrollY = useThrottle(scrollY, 100);
useEffect(() => {
const handleScroll = () => setScrollY(window.scrollY);
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
// This will only update every 100ms, even if scroll fires more frequently
useEffect(() => {
console.log('Throttled scroll position:', throttledScrollY);
}, [throttledScrollY]);
}
Throttle vs Debounce
- Throttle: Executes at regular intervals (e.g., every 100ms)
- Debounce: Waits for a pause before executing (e.g., after user stops typing)
Use Cases
- Scroll event handlers
- Window resize listeners
- Mouse move tracking
- API polling at intervals
- Limiting expensive calculations
Notes
- Throttle ensures regular execution, while debounce waits for inactivity.
- Choose throttle when you need periodic updates.
- Choose debounce when you want to wait for the user to finish.
Throttling is perfect for scenarios where you need consistent, periodic updates rather than waiting for a pause in activity.