Skip to content

Instantly share code, notes, and snippets.

@tomslutsky
Last active March 20, 2024 20:58
Show Gist options
  • Star 19 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save tomslutsky/f87a253a1dc43a1797306a79243a25ed to your computer and use it in GitHub Desktop.
Save tomslutsky/f87a253a1dc43a1797306a79243a25ed to your computer and use it in GitHub Desktop.
import { useEffect, useState } from "react";
import {
LoaderFunction,
useLoaderData,
json,
useSubmit,
useTransition,
useLocation
} from "remix";
import { useDebounce } from './useDebounce';
export default function Index() {
let { entries, q } = useLoaderData();
let [query, setQuery] = useState(q);
let [debouncedQuery, isDebouncing] = useDebounce(query, 500);
let location = useLocation()
let submit = useSubmit();
let transition = useTransition();
useEffect(() => {
let searchParams = new URLSearchParams(location.search);
if (debouncedQuery) {
searchParams.set("q", debouncedQuery);
} else {
searchParams.delete("q");
}
submit(searchParams);
}, [debouncedQuery]);
return (
<div>
<input
type="search"
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
<span>
{isDebouncing || transition.type === "loaderSubmission"
? "searching..."
: null}
</span>
<ul>
{entries.map((entry) => {
<li key={entry.id}>{entry.name}</li>;
})}
</ul>
</div>
);
}
export let loader: LoaderFunction = async ({ request }) => {
let url = new URL(request.url);
let { q } = Object.fromEntries(url.searchParams);
let entries = await getEntriesByQuerystring(q);
return json({ q, entries });
};
function useDebounce<T = any>(value: T, delay: number): [T, boolean] {
// State and setters for debounced value
const [debouncedValue, setDebouncedValue] = useState(value);
let [isDebouncing, setDebouncing] = useState(false);
useEffect(
() => {
// Update debounced value after delay
setDebouncing(true);
const handler = setTimeout(() => {
setDebouncing(false);
setDebouncedValue(value);
}, delay);
// Cancel the timeout if value changes (also on delay change or unmount)
// This is how we prevent debounced value from updating if value is changed ...
// .. within the delay period. Timeout gets cleared and restarted.
return () => {
clearTimeout(handler);
};
},
[value, delay] // Only re-call effect if value or delay changes
);
return [debouncedValue, isDebouncing];
}
export {useDebounce}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment