Open In App

How to use Debouncing and Throttling with React Hooks ?

Last Updated : 27 Mar, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

In React applications, managing user input effectively is crucial for creating a smooth and responsive user experience. Two common techniques for handling user input efficiently are debouncing and throttling. In this article, we’ll explore how to implement debouncing and throttling in React using hooks, with easy-to-understand examples. We’ll also incorporate the JSON Placeholder API to demonstrate real-world usage scenarios.

Prerequisites:

Understanding Debouncing and Throttling:

Debouncing and throttling are both strategies to control the rate at which a function is executed in response to repeated events, such as user input.

  • Debouncing ensures that a function is only called after a certain amount of time has passed since the last invocation, effectively delaying the execution until the user stops typing.
  • Throttling limits the frequency of function calls to a specified interval, ensuring that the function is not invoked more than once during the interval.

Different use cases:

Throttling:

  • Handling scroll events: Throttling can be used to limit the frequency of scroll event handlers, ensuring that they are not executed too frequently and leading to a smoother scrolling experience.
  • Preventing button spamming: Throttling can be applied to button click handlers to prevent users from spamming buttons and triggering multiple actions in quick succession.
  • Rate limiting API requests: Throttling can be used to limit the rate of API requests to a server, preventing overload and ensuring that the server can handle the incoming requests efficiently.
  • Implementing autocomplete functionality: Throttling can be useful when implementing autocomplete functionality, ensuring that API requests to fetch autocomplete suggestions are not sent too frequently while the user is typing.
  • Managing resize events: Throttling can be applied to window resize event handlers to prevent excessive recalculations and layout updates, improving performance.

Debouncing:

  • Implementing search functionality: Debouncing can be used in search input fields to delay sending search queries to the server until the user has finished typing, reducing the number of unnecessary API requests.
  • Filtering input validation: Debouncing can be applied to input validation logic to delay validation checks until the user has stopped typing, improving the user experience by reducing immediate error feedback.
  • Delaying expensive computations: Debouncing can be used to delay the execution of expensive computations, such as resizing images or processing large datasets, until the user has finished providing input.
  • Handling keypress events: Debouncing can be useful for handling keypress events, such as in autocomplete or typeahead functionality, to ensure that the search query is only updated after a brief pause in typing.
  • Implementing delayed actions: Debouncing can be used to implement delayed actions, such as submitting a form or triggering animations, to ensure that they are only performed after a specified delay, even if the user interacts with the interface multiple times.

Implementing Debouncing and Throttling with React Hooks:

Let’s consider a scenario where we have a search input field in a React component that fetches data from the JSON Placeholder API as the user types. We’ll use debouncing to delay the API request until the user pauses typing and throttling to limit the frequency of API requests.

This component allows users to:

  • Toggle between debouncing and throttling using a checkbox.
  • Type in a search input to see how debouncing or throttling affects API calls.
  • View the status message which dynamically changes to “Debouncing…”, “Throttling…”, or “Waiting for input…” based on the current input handling method and user activity.
Javascript
import React, { useState, useEffect } from 'react';
import axios from 'axios';

const SearchComponent = () => {
    const [query, setQuery] = useState('');
    const [results, setResults] = useState([]);
    const [loading, setLoading] = useState(false);
    const [isThrottling, setIsThrottling] = useState(false);
    const [inputStatus, setInputStatus] = 
                                    useState('Waiting for input...');

    // Debounce function
    const debounce = (func, delay) => {
        let timer;
        return (...args) => {
            clearTimeout(timer);
            timer = setTimeout(() => {
                func(...args);
            }, delay);
        };
    };

    // Throttle function
    const throttle = (func, delay) => {
        let lastCall = 0;
        return (...args) => {
            const now = new Date().getTime();
            if (now - lastCall < delay) {
                return;
            }
            lastCall = now;
            func(...args);
        };
    };

    useEffect(() => {
        const fetchData = async () => {
            if (!query) {
                setResults([]);
                setLoading(false);
                return;
            }
            setLoading(true);
            try {
                const response = await axios.get(`
https://jsonplaceholder.typicode.com/posts?title_like=${query}`);
                setResults(response.data);
                setLoading(false);
            } catch (error) {
                console.error('Error fetching data:', error);
                setLoading(false);
            }
        };

        const debouncedFetch = debounce(fetchData, 500);
        const throttledFetch = throttle(fetchData, 1000);

        if (isThrottling) {
            throttledFetch();
            setInputStatus('Throttling...');
        } else {
            debouncedFetch();
            setInputStatus('Debouncing...');
        }

        const timer = setTimeout(() => {
            setInputStatus('Waiting for input...');
        }, isThrottling ? 1000 : 500);

        return () => clearTimeout(timer);
    }, [query, isThrottling]);

    return (
        <div>
            <label>
                Toggle Throttling/Debouncing:
                <input
                    type="checkbox"
                    checked={isThrottling}
                    onChange={() => setIsThrottling(!isThrottling)}
                />
            </label>
            <input
                type="text"
                placeholder="Search..."
                value={query}
                onChange={(e) => setQuery(e.target.value)}
            />
            <p>{inputStatus}</p>
            {
                loading ?
                    <p>Loading...</p> :
                    <ul>{results.map((result) =>
                        <li key={result.id}>{result.title}</li>
                    )}
                    </ul>
            }
        </div>
    );
};

export default SearchComponent;

Output:

Untitled-design-(36)

Output

Conclusion:

Debouncing and throttling are powerful techniques for managing user input and optimizing API requests in React applications. By incorporating these strategies with React hooks, we can create more efficient and responsive user interfaces. With the easy-to-understand example provided in this article, even beginners can grasp the concept of debouncing and throttling and apply them to their React projects.



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads