{"id":1659,"date":"2024-07-08T12:48:33","date_gmt":"2024-07-08T12:48:33","guid":{"rendered":"https:\/\/www.vibidsoft.com\/blog\/?p=1659"},"modified":"2024-07-08T12:48:36","modified_gmt":"2024-07-08T12:48:36","slug":"how-to-debounce-throttle-a-callback-with-react-hooks","status":"publish","type":"post","link":"https:\/\/www.vibidsoft.com\/blog\/how-to-debounce-throttle-a-callback-with-react-hooks\/","title":{"rendered":"How to Debounce\/Throttle a Callback with React Hooks"},"content":{"rendered":"\n<p>In modern web development, building responsive and performant user interfaces is paramount. React, a popular library for building user interfaces, offers a powerful way to handle complex state management and side effects through hooks. Among these hooks, <code>useEffect<\/code>, <code>useCallback<\/code>, and <code>useState<\/code> are frequently used to manage component logic effectively.<\/p>\n\n\n\n<p>One common requirement in web applications is to control how often a function is called in response to events, such as scrolling or typing. This is where debouncing and throttling come into play. In this blog post, we&#8217;ll explore how to debounce and throttle a callback function using React Hooks, ensuring that your application remains responsive and performant.<\/p>\n\n\n\n<h2>What Are Debouncing and Throttling?<\/h2>\n\n\n\n<h3>Debouncing<\/h3>\n\n\n\n<p>Debouncing is a technique used to ensure that a function is not called too frequently. It delays the execution of the function until a specified amount of time has passed since it was last invoked. This is particularly useful for handling events that can fire rapidly, such as keystrokes in a search input. For instance, if a user is typing in a search bar, you might want to wait until they stop typing before making an API call to fetch search results.<\/p>\n\n\n\n<h3>Throttling<\/h3>\n\n\n\n<p>Throttling, on the other hand, limits the number of times a function can be called over a certain period. It ensures that a function is called at most once every specified interval. This is useful for scenarios like handling window resizing or scrolling events, where you want to perform an action at regular intervals, rather than every time the event is triggered.<\/p>\n\n\n\n<h2>Debouncing with React Hooks<\/h2>\n\n\n\n<p>To debounce a callback function in a React component, we can create a custom hook. Let\u2019s walk through how to implement a <code>useDebounce<\/code> hook.<\/p>\n\n\n\n<h3>Step 1: Creating the <code>useDebounce<\/code> Hook<\/h3>\n\n\n\n<p>We\u2019ll start by defining a <code>useDebounce<\/code> hook that takes a callback and a delay. This hook will return a debounced version of the callback function.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">jsxCopy code<code>import { useEffect, useCallback, useRef } from 'react';\n\nconst useDebounce = (callback, delay) =&gt; {\n  const handlerRef = useRef();\n\n  const debouncedCallback = useCallback((...args) =&gt; {\n    if (handlerRef.current) {\n      clearTimeout(handlerRef.current);\n    }\n    handlerRef.current = setTimeout(() =&gt; {\n      callback(...args);\n    }, delay);\n  }, [callback, delay]);\n\n  \/\/ Cleanup\n  useEffect(() =&gt; {\n    return () =&gt; {\n      if (handlerRef.current) {\n        clearTimeout(handlerRef.current);\n      }\n    };\n  }, []);\n\n  return debouncedCallback;\n};\n\nexport default useDebounce;\n<\/code><\/pre>\n\n\n\n<h3>Step 2: Using the <code>useDebounce<\/code> Hook in a Component<\/h3>\n\n\n\n<p>Let\u2019s use the <code>useDebounce<\/code> hook in a simple component that fetches search results as the user types in an input field.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">jsxCopy code<code>import React, { useState, useCallback } from 'react';\nimport useDebounce from '.\/useDebounce';\n\nconst SearchComponent = () =&gt; {\n  const [query, setQuery] = useState('');\n  const [results, setResults] = useState([]);\n\n  const fetchResults = async (searchQuery) =&gt; {\n    \/\/ Simulate an API call\n    const response = await fetch(`https:\/\/api.example.com\/search?q=${searchQuery}`);\n    const data = await response.json();\n    setResults(data.results);\n  };\n\n  const debouncedFetchResults = useDebounce(fetchResults, 500);\n\n  const handleChange = (event) =&gt; {\n    const value = event.target.value;\n    setQuery(value);\n    debouncedFetchResults(value);\n  };\n\n  return (\n    &lt;div&gt;\n      &lt;input\n        type=\"text\"\n        value={query}\n        onChange={handleChange}\n        placeholder=\"Search...\"\n      \/&gt;\n      &lt;ul&gt;\n        {results.map((result) =&gt; (\n          &lt;li key={result.id}&gt;{result.name}&lt;\/li&gt;\n        ))}\n      &lt;\/ul&gt;\n    &lt;\/div&gt;\n  );\n};\n\nexport default SearchComponent;\n<\/code><\/pre>\n\n\n\n<p>In this example, as the user types in the input field, the <code>handleChange<\/code> function updates the <code>query<\/code> state and calls the debounced version of <code>fetchResults<\/code>. The API call is only made after the user stops typing for 500 milliseconds.<\/p>\n\n\n\n<h2>Throttling with React Hooks<\/h2>\n\n\n\n<p>Similar to debouncing, we can create a custom hook for throttling. The <code>useThrottle<\/code> hook will ensure that a function is called at most once every specified interval.<\/p>\n\n\n\n<h3>Step 1: Creating the <code>useThrottle<\/code> Hook<\/h3>\n\n\n\n<p>Here\u2019s how you can define a <code>useThrottle<\/code> hook:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">jsxCopy code<code>import { useEffect, useCallback, useRef } from 'react';\n\nconst useThrottle = (callback, limit) =&gt; {\n  const lastCallRef = useRef(0);\n\n  const throttledCallback = useCallback((...args) =&gt; {\n    const now = Date.now();\n    if (now - lastCallRef.current &gt;= limit) {\n      lastCallRef.current = now;\n      callback(...args);\n    }\n  }, [callback, limit]);\n\n  return throttledCallback;\n};\n\nexport default useThrottle;\n<\/code><\/pre>\n\n\n\n<h3>Step 2: Using the <code>useThrottle<\/code> Hook in a Component<\/h3>\n\n\n\n<p>Let\u2019s use the <code>useThrottle<\/code> hook in a component that handles a window resize event.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">jsxCopy code<code>import React, { useState, useEffect } from 'react';\nimport useThrottle from '.\/useThrottle';\n\nconst ResizeComponent = () =&gt; {\n  const [windowWidth, setWindowWidth] = useState(window.innerWidth);\n\n  const handleResize = () =&gt; {\n    setWindowWidth(window.innerWidth);\n  };\n\n  const throttledHandleResize = useThrottle(handleResize, 1000);\n\n  useEffect(() =&gt; {\n    window.addEventListener('resize', throttledHandleResize);\n    return () =&gt; {\n      window.removeEventListener('resize', throttledHandleResize);\n    };\n  }, [throttledHandleResize]);\n\n  return (\n    &lt;div&gt;\n      &lt;h1&gt;Window width: {windowWidth}&lt;\/h1&gt;\n    &lt;\/div&gt;\n  );\n};\n\nexport default ResizeComponent;\n<\/code><\/pre>\n\n\n\n<p>In this example, the <code>handleResize<\/code> function updates the <code>windowWidth<\/code> state whenever the window is resized. The <code>throttledHandleResize<\/code> ensures that the function is called at most once every 1000 milliseconds.<\/p>\n\n\n\n<h2>Combining Debounce and Throttle<\/h2>\n\n\n\n<p>There might be scenarios where you need to combine debouncing and throttling. For example, you might want to throttle API calls but debounce search input updates. Combining these hooks can help you achieve more refined control over function execution.<\/p>\n\n\n\n<h3>Example: Combining Debounce and Throttle<\/h3>\n\n\n\n<p>Let\u2019s create a component that uses both debouncing and throttling. In this example, we\u2019ll debounce user input and throttle API calls.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">jsxCopy code<code>import React, { useState } from 'react';\nimport useDebounce from '.\/useDebounce';\nimport useThrottle from '.\/useThrottle';\n\nconst SearchThrottleDebounceComponent = () =&gt; {\n  const [query, setQuery] = useState('');\n  const [results, setResults] = useState([]);\n\n  const fetchResults = async (searchQuery) =&gt; {\n    const response = await fetch(`https:\/\/api.example.com\/search?q=${searchQuery}`);\n    const data = await response.json();\n    setResults(data.results);\n  };\n\n  const throttledFetchResults = useThrottle(fetchResults, 1000);\n  const debouncedFetchResults = useDebounce(throttledFetchResults, 500);\n\n  const handleChange = (event) =&gt; {\n    const value = event.target.value;\n    setQuery(value);\n    debouncedFetchResults(value);\n  };\n\n  return (\n    &lt;div&gt;\n      &lt;input\n        type=\"text\"\n        value={query}\n        onChange={handleChange}\n        placeholder=\"Search...\"\n      \/&gt;\n      &lt;ul&gt;\n        {results.map((result) =&gt; (\n          &lt;li key={result.id}&gt;{result.name}&lt;\/li&gt;\n        ))}\n      &lt;\/ul&gt;\n    &lt;\/div&gt;\n  );\n};\n\nexport default SearchThrottleDebounceComponent;\n<\/code><\/pre>\n\n\n\n<p>In this component, the <code>fetchResults<\/code> function is throttled to ensure it\u2019s called at most once every 1000 milliseconds. The <code>debouncedFetchResults<\/code> further debounces this throttled function, ensuring that it\u2019s only called 500 milliseconds after the user stops typing. This combination helps in controlling the frequency of API calls while responding to user input efficiently.<\/p>\n\n\n\n<h2>Conclusion<\/h2>\n\n\n\n<p>Debouncing and throttling are essential techniques for optimizing the performance of web applications, especially when dealing with rapid events like input changes, scrolling, or resizing. By leveraging React Hooks, we can create reusable and efficient debounced and throttled functions tailored to the needs of our applications.<\/p>\n\n\n\n<h3>Key Takeaways<\/h3>\n\n\n\n<ol><li><strong>Debouncing<\/strong> delays the execution of a function until a certain amount of time has passed since it was last invoked.<\/li><li><strong>Throttling<\/strong> ensures that a function is called at most once every specified interval.<\/li><li>Custom hooks like <code>useDebounce<\/code> and <code>useThrottle<\/code> can encapsulate debouncing and throttling logic, making it easy to apply these techniques in your React components.<\/li><li>Combining debouncing and throttling allows you to refine the control over function execution, especially useful for scenarios like search inputs and API calls.<\/li><\/ol>\n\n\n\n<p>Implementing these techniques correctly can lead to smoother and more responsive user interfaces, enhancing the overall user experience of your application.<\/p>\n\n\n\n<p>Happy coding!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In modern web development, building responsive and performant user interfaces is paramount. React, a popular library for building user interfaces, offers a powerful way to handle complex state management and side effects through hooks. Among these hooks, useEffect, useCallback, and&#8230; <a class=\"more-link\" href=\"https:\/\/www.vibidsoft.com\/blog\/how-to-debounce-throttle-a-callback-with-react-hooks\/\">Continue Reading &rarr;<\/a><\/p>\n","protected":false},"author":1,"featured_media":1660,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0},"categories":[156],"tags":[1920,1928,1919,1916,1918,1917,1926,1921,1929,1925,1930,1923,1927,1924,1922],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.vibidsoft.com\/blog\/wp-json\/wp\/v2\/posts\/1659"}],"collection":[{"href":"https:\/\/www.vibidsoft.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.vibidsoft.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.vibidsoft.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.vibidsoft.com\/blog\/wp-json\/wp\/v2\/comments?post=1659"}],"version-history":[{"count":1,"href":"https:\/\/www.vibidsoft.com\/blog\/wp-json\/wp\/v2\/posts\/1659\/revisions"}],"predecessor-version":[{"id":1661,"href":"https:\/\/www.vibidsoft.com\/blog\/wp-json\/wp\/v2\/posts\/1659\/revisions\/1661"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.vibidsoft.com\/blog\/wp-json\/wp\/v2\/media\/1660"}],"wp:attachment":[{"href":"https:\/\/www.vibidsoft.com\/blog\/wp-json\/wp\/v2\/media?parent=1659"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.vibidsoft.com\/blog\/wp-json\/wp\/v2\/categories?post=1659"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.vibidsoft.com\/blog\/wp-json\/wp\/v2\/tags?post=1659"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}