Skip to content

Instantly share code, notes, and snippets.

@cfj
Last active March 3, 2023 14:46
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cfj/c566f645ab3b2efb0a9fc0919847f689 to your computer and use it in GitHub Desktop.
Save cfj/c566f645ab3b2efb0a9fc0919847f689 to your computer and use it in GitHub Desktop.
import { useState, useRef } from 'react';
import styles from '../styles/DebouncedInputFetchDemo.module.css';
const lookupOrder = async (orderNumber, fetchOptions = {}) => {
const response = await fetch(`/api/demo?orderNo=${orderNumber}&delay=3`, {
method: 'GET',
...fetchOptions
});
return response.json();
};
const DebouncedInputFetchDemo = () => {
const debounceDelay = 750;
const debounceTimer = useRef(0);
const controller = useRef();
const [loading, setLoading] = useState(false);
const [orderNumber, setOrderNumber] = useState('');
const [order, setOrder] = useState();
const performanceEntries =
typeof window !== 'undefined' &&
window.performance &&
window.performance.getEntries().filter((e) => e.initiatorType === 'fetch' && e.name.includes('demo'));
const debouncedFetch = (orderNumber) => {
setOrderNumber(orderNumber);
clearTimeout(debounceTimer.current);
controller.current?.abort();
controller.current = new AbortController();
debounceTimer.current = setTimeout(async () => {
setOrder(undefined);
try {
if (orderNumber) {
setLoading(true);
const order = await lookupOrder(orderNumber, {
signal: controller.current.signal
});
setOrder(order);
}
} catch (err) {
if (err instanceof Error && err.name !== 'AbortError') {
setError(err);
}
} finally {
setLoading(false);
}
}, debounceDelay);
};
return (
<div className={styles.debouncedForm}>
<form>
<label htmlFor="order-no">Order number</label>
<input
autoComplete="off"
type="text"
id="order-no"
className={loading ? styles.loading : order ? styles.success : ''}
value={orderNumber}
onChange={(e) => debouncedFetch(e.target.value)}
/>
{order ? <span className="text-green-500 ml-2">Order found: {order.order}</span> : null}
</form>
{(performanceEntries && performanceEntries.length) || loading ? (
<>
<h2>Requests</h2>
<div>
<ul>
{performanceEntries.map((entry, i) => (
<li key={i}>
{entry.connectEnd ? (
<span className="text-green-500">200 OK</span>
) : (
<span className="text-red-400">Cancelled by AbortController</span>
)}
</li>
))}
{loading ? (
<li>
<span className="text-yellow-500">Pending...</span>
</li>
) : null}
</ul>
</div>
</>
) : null}
</div>
);
};
export default DebouncedInputFetchDemo;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment