avatar

Le Do Nghiem

Software Engineer

  • About me
  • Books
  • Snippets
  • Blog

© 2026 Le Do Nghiem. All rights reserved.

Contact |

Back to Snippets

useThrottle Hook

A React hook to throttle function calls, limiting execution frequency.

LanguageTypeScript
Last UpdatedDec 21, 2025
use-throttle.ts
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;
}

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

  • lastRan tracks 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.

Previous Snippet

useWindowSize Hook

Next Snippet

usePrevious Hook