Skip to content

Commit c942937

Browse files
Convert useDebounce hook to TS
1 parent c2765c3 commit c942937

File tree

1 file changed

+101
-0
lines changed

1 file changed

+101
-0
lines changed

src/pages/useDebounce.md

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ title: useDebounce
44
date: "2018-11-09"
55
gist: https://gist.github.com/gragland/e50346f02e7edf4f81cc0bda33d3cae6
66
sandbox: https://codesandbox.io/s/711r1zmq50
7+
isMultilingual: true
78
---
89

910
This hook allows you to debounce any fast changing value. The debounced value will only reflect the latest value when the useDebounce hook has not been called for the specified time period. When used in conjunction with useEffect, as we do in the recipe below, you can easily ensure that expensive operations like API calls are not executed too frequently. The example below allows you to search the Marvel Comic API and uses useDebounce to prevent API calls from being fired on every keystroke. Be sure to check out the [CodeSandbox demo](https://codesandbox.io/s/711r1zmq50) for this one. Hook code and inspiration from [github.com/xnimorz/use-debounce](https://github.com/xnimorz/use-debounce).
@@ -105,3 +106,103 @@ function useDebounce(value, delay) {
105106
return debouncedValue;
106107
}
107108
```
109+
110+
```typescript jsx
111+
import { useState, useEffect, useRef } from "react";
112+
113+
// Usage
114+
function App() {
115+
// State and setters for ...
116+
// Search term
117+
const [searchTerm, setSearchTerm] = useState<string>("");
118+
// API search results
119+
const [results, setResults] = useState<any[]>([]);
120+
// Searching status (whether there is pending API request)
121+
const [isSearching, setIsSearching] = useState<boolean>(false);
122+
// Debounce search term so that it only gives us latest value ...
123+
// ... if searchTerm has not been updated within last 500ms.
124+
// The goal is to only have the API call fire when user stops typing ...
125+
// ... so that we aren't hitting our API rapidly.
126+
// We pass generic type, this case string
127+
const debouncedSearchTerm: string = useDebounce<string>(searchTerm, 500);
128+
129+
// Effect for API call
130+
useEffect(
131+
() => {
132+
if (debouncedSearchTerm) {
133+
setIsSearching(true);
134+
searchCharacters(debouncedSearchTerm).then((results) => {
135+
setIsSearching(false);
136+
setResults(results);
137+
});
138+
} else {
139+
setResults([]);
140+
}
141+
},
142+
[debouncedSearchTerm] // Only call effect if debounced search term changes
143+
);
144+
145+
return (
146+
<div>
147+
<input
148+
placeholder="Search Marvel Comics"
149+
onChange={(e: React.FormEvent<HTMLInputElement>) => setSearchTerm(e.target.value)}
150+
/>
151+
152+
{isSearching && <div>Searching ...</div>}
153+
154+
{results.map((result) => (
155+
<div key={result.id}>
156+
<h4>{result.title}</h4>
157+
<img
158+
src={`${result.thumbnail.path}/portrait_incredible.${result.thumbnail.extension}`}
159+
/>
160+
</div>
161+
))}
162+
</div>
163+
);
164+
}
165+
166+
// API search function
167+
function searchCharacters(search: string): Promise<any[]> {
168+
const apiKey:string = "f9dfb1e8d466d36c27850bedd2047687";
169+
return fetch(
170+
`https://gateway.marvel.com/v1/public/comics?apikey=${apiKey}&titleStartsWith=${search}`,
171+
{
172+
method: "GET",
173+
}
174+
)
175+
.then((r) => r.json())
176+
.then((r) => r.data.results)
177+
.catch((error) => {
178+
console.error(error);
179+
return [];
180+
});
181+
}
182+
183+
// Hook
184+
// T is a generic type for value parameter, our case this will be string
185+
function useDebounce<T>(value: T, delay: number): T {
186+
// State and setters for debounced value
187+
const [debouncedValue, setDebouncedValue] = useState<T>(value);
188+
189+
useEffect(
190+
() => {
191+
// Update debounced value after delay
192+
const handler = setTimeout(() => {
193+
setDebouncedValue(value);
194+
}, delay);
195+
196+
// Cancel the timeout if value changes (also on delay change or unmount)
197+
// This is how we prevent debounced value from updating if value is changed ...
198+
// .. within the delay period. Timeout gets cleared and restarted.
199+
return () => {
200+
clearTimeout(handler);
201+
};
202+
},
203+
[value, delay] // Only re-call effect if value or delay changes
204+
);
205+
206+
return debouncedValue;
207+
}
208+
```

0 commit comments

Comments
 (0)