React Debounce 使用 React Hooks 进行去抖动

2025-05-24

React Debounce使用 React Hooks 进行去抖动

今天我将向你展示如何构建一个 useDebounce React Hook,它能够非常轻松地对 API 调用进行去抖动,从而确保它们不会执行得太频繁。我还制作了一个使用这个 Hook 的演示。它搜索 Marvel Comic API,并使用 useDebounce 来防止每次按键时都触发 API 调用。

演示截图

是不是很漂亮?好了,现在开始代码吧!

首先,让我们弄清楚如何使用这个钩子,并以此为指导来实际实现钩子逻辑。我们设计这个钩子的目的不是对 API 请求的调用进行去抖动处理,而是对组件渲染函数中的任何值进行去抖动处理。然后,我们将结合使用 和 ,useEffect以便在输入值发生变化时触发新的 API 请求。本代码示例假设读者对useState和钩子有所了解,你可以在React Hook 文档useEffect中了解它们



import React, { useState, useEffect } from 'react';
import useDebounce from './use-debounce';

// Usage
function App() {
  // State and setter for search term
  const [searchTerm, setSearchTerm] = useState('');
  // State and setter for search results
  const [results, setResults] = useState([]);
  // State for search status (whether there is a pending API request)
  const [isSearching, setIsSearching] = useState(false);

  // Now we call our hook, passing in the current searchTerm value.
  // The hook will only return the latest value (what we passed in) ...
  // ... if it's been more than 500ms since it was last called.
  // Otherwise, it will return the previous value of searchTerm.
  // The goal is to only have the API call fire when user stops typing ...
  // ... so that we aren't hitting our API rapidly.
  const debouncedSearchTerm = useDebounce(searchTerm, 500);

  // Here's where the API call happens
  // We use useEffect since this is an asynchronous action
  useEffect(
    () => {
      // Make sure we have a value (user has entered something in input)
      if (debouncedSearchTerm) {
        // Set isSearching state
        setIsSearching(true);
        // Fire off our API call
        searchCharacters(debouncedSearchTerm).then(results => {
          // Set back to false since request finished
          setIsSearching(false);
          // Set results state
          setResults(results);
        });
      } else {
        setResults([]);
      }
    },
    // This is the useEffect input array
    // Our useEffect function will only execute if this value changes ...
    // ... and thanks to our hook it will only change if the original ...
    // value (searchTerm) hasn't changed for more than 500ms.
    [debouncedSearchTerm]
  );

  // Pretty standard UI with search input and results
  return (
    <div>
      <input
        placeholder="Search Marvel Comics"
        onChange={e => setSearchTerm(e.target.value)}
      />

      {isSearching && <div>Searching ...</div>}

      {results.map(result => (
        <div key={result.id}>
          <h4>{result.title}</h4>
          <img
            src={`${result.thumbnail.path}/portrait_incredible.${
              result.thumbnail.extension
            }`}
          />
        </div>
      ))}
    </div>
  );
}

// API search function
function searchCharacters(search) {
  const apiKey = 'f9dfb1e8d466d36c27850bedd2047687';
  const queryString `apikey=${apiKey}&titleStartsWith=${search}`;
  return fetch(
    `https://gateway.marvel.com/v1/public/comics?${queryString}`,
    {
      method: 'GET'
    }
  )
    .then(r => r.json())
    .then(r => r.data.results)
    .catch(error => {
      console.error(error);
      return [];
    });
}



Enter fullscreen mode Exit fullscreen mode

好的,看起来不错!现在让我们构建实际的钩子,以便我们的应用程序正常运行。



import React, { useState, useEffect } from 'react';

// Our hook
export default function useDebounce(value, delay) {
  // State and setters for debounced value
  const [debouncedValue, setDebouncedValue] = useState(value);

  useEffect(
    () => {
      // Set debouncedValue to value (passed in) after the specified delay
      const handler = setTimeout(() => {
        setDebouncedValue(value);
      }, delay);

      // Return a cleanup function that will be called every time ...
      // ... useEffect is re-called. useEffect will only be re-called ...
      // ... if value changes (see the inputs array below). 
      // This is how we prevent debouncedValue from changing if value is ...
      // ... changed within the delay period. Timeout gets cleared and restarted.
      // To put it in context, if the user is typing within our app's ...
      // ... search box, we don't want the debouncedValue to update until ...
      // ... they've stopped typing for more than 500ms.
      return () => {
        clearTimeout(handler);
      };
    },
    // Only re-call effect if value changes
    // You could also add the "delay" var to inputs array if you ...
    // ... need to be able to change that dynamically.
    [value] 
  );

  return debouncedValue;
}



Enter fullscreen mode Exit fullscreen mode

就这样!我们现在有了一个去抖钩子,可以用来在组件主体中对任何值进行去抖动处理。然后,可以将去抖动值(useEffect而不是非去抖动值)添加到 的输入数组中,以限制该效果的调用频率。

还可以看看我的React 代码库生成器。它将提供美观的 UI、身份验证、数据库、支付等功能。成千上万的 React 开发者使用它来快速构建和发布应用。

文章来源:https://dev.to/gabe_ragland/debouncing-with-react-hooks-jci
PREV
我的开发工具如何在 4 天内赚到 10,041 美元
NEXT
可能是最有用的 CSS 技巧