From 3a13d94b71d51de4ab3c27694248f1d7c34cbacc Mon Sep 17 00:00:00 2001 From: Adam Moussa <166072409+amoussa1229@users.noreply.github.com> Date: Thu, 16 Apr 2026 19:16:04 -0400 Subject: [PATCH] Add 600ms debounce to search in usePaginatedList - Typing updates the input immediately but delays the API call - Table keeps showing current results until the search settles - Resets to page 1 when search changes - Applies to all list pages using the shared hook --- src/hooks/usePaginatedList.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/hooks/usePaginatedList.js b/src/hooks/usePaginatedList.js index ddc781a9..4a5a05a0 100644 --- a/src/hooks/usePaginatedList.js +++ b/src/hooks/usePaginatedList.js @@ -1,27 +1,38 @@ -import { useCallback, useEffect, useMemo, useState } from "react"; +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; export default function usePaginatedList(fetchFn, extraParams = {}) { const [rows, setRows] = useState([]); const [search, setSearch] = useState(""); + const [debouncedSearch, setDebouncedSearch] = useState(""); const [page, setPage] = useState(1); const [pageSize, setPageSize] = useState(12); const [totalCount, setTotalCount] = useState(0); const [loading, setLoading] = useState(true); const [err, setErr] = useState(""); + const debounceRef = useRef(null); const extraKey = JSON.stringify(extraParams); + useEffect(() => { + if (debounceRef.current) clearTimeout(debounceRef.current); + debounceRef.current = setTimeout(() => { + setDebouncedSearch(search); + setPage(1); + }, 600); + return () => clearTimeout(debounceRef.current); + }, [search]); + const reload = useCallback(() => { setLoading(true); setErr(""); - fetchFn({ search, page, pageSize, ...extraParams }) + fetchFn({ search: debouncedSearch, page, pageSize, ...extraParams }) .then(({ rows, totalCount }) => { setRows(rows); setTotalCount(totalCount); }) .catch((e) => setErr(e.message || "Failed to load")) .finally(() => setLoading(false)); - }, [fetchFn, search, page, pageSize, extraKey]); + }, [fetchFn, debouncedSearch, page, pageSize, extraKey]); useEffect(() => { reload(); }, [reload]);