fix(feed): stop search-box flicker (keepPreviousData + debounced query)
Typing in the search box changed the feed/count/facets query keys on every keystroke, so each query dropped to its loading state and blanked the content — the whole feed area flickered. Debounce the search term feeding the queries (the input still updates instantly) so they only re-run after a pause, and keep previous results on screen during a refetch via placeholderData: keepPreviousData, so the feed and tag counts update in place without blanking.
This commit is contained in:
parent
8b19faaed1
commit
74cf31b58d
3 changed files with 35 additions and 8 deletions
|
|
@ -1,10 +1,11 @@
|
|||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useInfiniteQuery, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { keepPreviousData, useInfiniteQuery, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { ArrowDown, ArrowUp, ArrowLeft, RefreshCw, Youtube } from "lucide-react";
|
||||
import { api, HttpError, type FeedFilters, type Video } from "../lib/api";
|
||||
import i18n from "../i18n";
|
||||
import { notify, resolveVideo } from "../lib/notifications";
|
||||
import { useDebounced } from "../lib/useDebounced";
|
||||
import VirtualFeed from "./VirtualFeed";
|
||||
import PlayerModal from "./PlayerModal";
|
||||
|
||||
|
|
@ -100,12 +101,19 @@ export default function Feed({
|
|||
|
||||
const ytActive = !!ytSearch;
|
||||
|
||||
// Debounce only the search term feeding the queries: the input still updates instantly (it
|
||||
// owns filters.q), but the feed/count keys settle after a pause, so typing doesn't refetch —
|
||||
// and re-fetched pages keep the previous results on screen, so the feed never blanks/flickers.
|
||||
const debouncedQ = useDebounced(filters.q, 300);
|
||||
const queryFilters: FeedFilters = { ...filters, q: debouncedQ };
|
||||
|
||||
const query = useInfiniteQuery({
|
||||
queryKey: ["feed", filters],
|
||||
queryFn: ({ pageParam }) => api.feed(filters, pageParam as string | null, PAGE),
|
||||
queryKey: ["feed", queryFilters],
|
||||
queryFn: ({ pageParam }) => api.feed(queryFilters, pageParam as string | null, PAGE),
|
||||
initialPageParam: null as string | null,
|
||||
getNextPageParam: (last) => last.next_cursor ?? undefined,
|
||||
enabled: !ytActive, // don't load the normal feed while showing live YouTube results
|
||||
placeholderData: keepPreviousData,
|
||||
});
|
||||
|
||||
// Live YouTube search results. Each page spends 100 quota units, so we never auto-paginate
|
||||
|
|
@ -135,10 +143,11 @@ export default function Feed({
|
|||
}, [query.dataUpdatedAt]);
|
||||
|
||||
const countQuery = useQuery({
|
||||
queryKey: ["feed-count", filters],
|
||||
queryFn: () => api.feedCount(filters),
|
||||
queryKey: ["feed-count", queryFilters],
|
||||
queryFn: () => api.feedCount(queryFilters),
|
||||
staleTime: 30_000,
|
||||
enabled: !ytActive,
|
||||
placeholderData: keepPreviousData,
|
||||
});
|
||||
|
||||
const { hasNextPage, isFetchingNextPage, fetchNextPage } = query;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue