From 0202c1caa9f850679d3cb1be8216fd38841886b7 Mon Sep 17 00:00:00 2001 From: Gauvain Date: Fri, 17 Jul 2026 17:44:16 +0200 Subject: [PATCH] fix(review): derive filter sheet pages from live query data, keep reset handler over forwarded props --- components/filters/ResetFiltersButton.tsx | 3 ++- components/filters/SharedFilterSheet.tsx | 27 +++++++---------------- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/components/filters/ResetFiltersButton.tsx b/components/filters/ResetFiltersButton.tsx index 1635f4dd1..c23d0c757 100644 --- a/components/filters/ResetFiltersButton.tsx +++ b/components/filters/ResetFiltersButton.tsx @@ -18,9 +18,10 @@ export const ResetFiltersButton: React.FC = ({ return ( diff --git a/components/filters/SharedFilterSheet.tsx b/components/filters/SharedFilterSheet.tsx index 3fe8392b7..c86c89043 100644 --- a/components/filters/SharedFilterSheet.tsx +++ b/components/filters/SharedFilterSheet.tsx @@ -167,7 +167,6 @@ const SharedFilterSheetContent: React.FC = ({ enabled: !!id && !!queryFn && !!queryKey, }); - const [data, setData] = useState([]); const [offset, setOffset] = useState(0); const [search, setSearch] = useState(""); @@ -187,6 +186,14 @@ const SharedFilterSheetContent: React.FC = ({ return results.slice(0, 100); }, [deferredSearch, _data, searchFilter]); + // Paginated window derived from the live query result ("load more" grows the + // window). No accumulated copy: a background refetch that removes options + // can't leave stale rows behind, and no per-item dedupe is needed. + const data = useMemo( + () => _data?.slice(0, offset + LIMIT) ?? [], + [_data, offset], + ); + useEffect(() => { if (!data || data.length === 0 || disableSearch) return; if (data.length > 15) { @@ -194,24 +201,6 @@ const SharedFilterSheetContent: React.FC = ({ } }, [data, disableSearch]); - // Loads data in batches of LIMIT from offset (efficient "load more"). - useEffect(() => { - if (!_data || _data.length === 0) return; - - const newData = [...data]; - for (let i = offset; i < Math.min(_data.length, offset + LIMIT); i++) { - const item = _data[i]; - // Option objects are recreated across renders → dedupe by value. - const exists = newData.some((existingItem) => - isEqual(existingItem, item), - ); - if (!exists) { - newData.push(item); - } - } - setData(newData); - }, [offset, _data]); - const renderData = useMemo(() => { if (deferredSearch.length > 0 && showSearch) return filteredData; return data;