今天,我將向您展示如何建立一個 useDebounce React Hook,它可以非常輕鬆地對 API 呼叫進行反跳操作,以確保它們不會執行得太頻繁。我還製作了一個使用我們的鉤子的演示。它搜尋 Marvel Comic API 並使用 useDebounce 來防止每次按鍵時觸發 API 呼叫。

示範截圖

很漂亮吧?好的,現在來看程式碼!

首先,讓我們弄清楚我們希望如何使用鉤子,然後我們可以讓它指導或實際實現鉤子邏輯。我們不會對 API 請求的呼叫進行反跳,而是設計這個鉤子來對元件渲染函數中的任何值進行反跳。然後,我們將其與useEffect結合起來,以便在輸入值變更時觸發新的 API 請求。此程式碼範例假設您對useStateuseEffect掛鉤有一定的了解,您可以在React Hook 文件中了解這些內容。

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 [];
    });
}

好吧,看起來不錯!現在讓我們建立實際的鉤子以便我們的應用程式能夠執行。

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;
}

現在你就擁有了!現在,我們有了一個去抖鉤子,可以使用它來對元件主體中的任何值進行去抖動。然後,可以將去抖值(而不是非去抖值)包含在useEffect的輸入陣列中,以限制呼叫該效果的頻率。

另請查看我的React 程式碼庫產生器。它會給你一個漂亮的使用者介面、身份驗證、資料庫、付款等等。成千上萬的 React 開發人員使用它來快速建立和啟動應用程式。


原文出處:https://dev.to/gabe_ragland/debouncing-with-react-hooks-jci


共有 0 則留言