发布于 2025-12-08 0 阅读
0

React Debounce 使用 React Hooks 进行去抖动

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