Explain Codes LogoExplain Codes Logo

How can I perform a debounce?

javascript
debounce
react-hooks
async-programming
Alex KataevbyAlex Kataev·Aug 28, 2024
TLDR
function debounce(func, wait) { let timeout; return function(...args) { clearTimeout(timeout); timeout = setTimeout(() => func.apply(this, args), wait); }; } // Usage example for a search input: const handleSearch = debounce(() => { // Perform search operations like you're looking for Waldo }, 300); document.getElementById('search-input').addEventListener('input', handleSearch);

This debounce function holds up the execution of func until wait milliseconds have elapsed since the last invocation. Boost your event handling with this for rapidly firing events, such as input or resize.

Debounce in React: Even better with hooks and async

Crank up your debounce experience in a React context by deploying a couple of handy strategies.

Use of useCallback for debounce in React

Make memoized debounced function with the help of useCallback:

const handleSearch = useCallback( debounce((searchTerm) => { // It's Google time! }, 300), [] // Leave dependencies array empty to initialize only once );

In functional components, pair side-effects with debounced callbacks using useEffect to make sure they pop at correct lifecycle stage.

SearchBox: Debounced onUpdate with controlled components

For controlled components, you need a method to update state without sluggish behavior.

const [searchTerm, setSearchTerm] = useState(''); const debouncedSearchTermUpdate = debounce(setSearchTerm, 300); const handleInputChange = (event) => { event.persist(); // Avoid React event pooling vanish trick debouncedSearchTermUpdate(event.target.value); };

Debounce with data streams: Observables to the rescue

When dealing with streams of data, consider observables such as RxJS:

const searchSubject = new Rx.Subject(); const debouncedSearch = searchSubject.pipe( debounceTime(300) ); debouncedSearch.subscribe((value) => { // Value arrived, light up the API! }); const handleInputChange = (event) => { searchSubject.next(event.target.value); };

Advanced Debounce: Be the Master

The provided visualization and basic implementation cover the fundamentals of debounce, but for those who want to command debounce scenarios, here are further refinements and nuances you should know about.

SyntheticEvent.persist() for React event pooling

If you're using React and dealing with SyntheticEvent, here's a pro-tip: use .persist(). Why? To make the event details survive the async delay period, critical for event-based debounce ops.

Dealing with async operations

When it's async party time, Awesome-debounce-promise stands tall managing promises. It ensures only the prom of the latest call will resolve and change the state.

import AwesomeDebouncePromise from 'awesome-debounce-promise'; const apiSearch = (query) => { // It's async API magic time! }; const debouncedApiSearch = AwesomeDebouncePromise(apiSearch, 300);

Side effects in functional components

To create side effects from debounced actions, get in the good books of useEffect. It keeps components reactive without making debounced callbacks clumsy.

Reusable debounced hooks

For lovers of reusability, creating custom hooks like useDebouncedValue or useDebouncedCallback packs debounce logic in a multi-use capsule.

function useDebouncedValue(value, delay) { const [debouncedValue, setDebouncedValue] = useState(value); useEffect(() => { const handler = setTimeout(() => { setDebouncedValue(value); // The wait is over, value's time to shine! }, delay); return () => { clearTimeout(handler); // Cleaning up, it's Debounce 101 }; }, [value, delay]); return debouncedValue; }