今天,我將向您展示如何建立一個 useDebounce React Hook,它可以非常輕鬆地對 API 呼叫進行反跳操作,以確保它們不會執行得太頻繁。我還製作了一個使用我們的鉤子的演示。它搜尋 Marvel Comic API 並使用 useDebounce 來防止每次按鍵時觸發 API 呼叫。
很漂亮吧?好的,現在來看程式碼!
首先,讓我們弄清楚我們希望如何使用鉤子,然後我們可以讓它指導或實際實現鉤子邏輯。我們不會對 API 請求的呼叫進行反跳,而是設計這個鉤子來對元件渲染函數中的任何值進行反跳。然後,我們將其與useEffect
結合起來,以便在輸入值變更時觸發新的 API 請求。此程式碼範例假設您對useState
和useEffect
掛鉤有一定的了解,您可以在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