Skip to content

Instantly share code, notes, and snippets.

@pratikdevdas
Forked from tomslutsky/debounced-search.tsx
Last active August 26, 2023 09:34
Show Gist options
  • Save pratikdevdas/14a8aee71a7de8a8e756c51324e1f079 to your computer and use it in GitHub Desktop.
Save pratikdevdas/14a8aee71a7de8a8e756c51324e1f079 to your computer and use it in GitHub Desktop.
supports v2 and updated a few hooks
import { useEffect, useState } from "react";
import {
LoaderFunction,
useLoaderData,
useSubmit,
useSearchParams,
useNavigation
} from "@remix-run/react";
import { useDebounce } from './useDebounce';
import { LoaderArgs, json } from "@remix-run/node";
export default function Index() {
let { entries, q } = useLoaderData();
let [query, setQuery] = useState(q);
let [debouncedQuery, isDebouncing] = useDebounce(query, 500);
let submit = useSubmit();
const [searchParams, setSearchParams] = useSearchParams()
let navigation = useNavigation();
useEffect(() => {
if (debouncedQuery) {
setSearchParams({ q: debouncedQuery })
} else {
setSearchParams()
}
}, [debouncedQuery]);
return (
<div>
<input
type="search"
value={query}
onChange={(e) => {
setQuery(e.target.value)}}
/>
<span>
{isDebouncing || navigation.state === "loading"
? "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