如何在React Query无限滚动中集成搜索功能?
结合搜索功能与React Query无限滚动
要将搜索功能与现有无限滚动结合,核心是让React Query根据搜索关键词重新触发分页查询,并重置分页状态。以下是具体实现步骤和修改后的代码:
关键修改点
- 将搜索关键词加入Query Key:React Query通过
queryKey区分不同查询,把搜索关键词加入后,每次搜索词变化时会自动清空旧分页数据,重新从第一页获取过滤结果。 - 在分页查询中传递搜索关键词:修改
queryFn,将搜索关键词传递给API请求,确保每次分页获取的都是过滤后的数据。 - 实现搜索输入的状态更新:让搜索栏回调函数更新搜索关键词状态,触发React Query重新查询。
- 可选:添加输入防抖:避免用户每输入一个字符就发起API请求,提升性能和体验。
修改后的完整代码
import { useState, useEffect } from 'react'; import { useInfiniteQuery } from '@tanstack/react-query'; import { useInView } from 'react-intersection-observer'; const CouponList = () => { const [query, setQuery] = useState<string>(""); const [debouncedQuery, setDebouncedQuery] = useState(query); const { ref, inView } = useInView(); // 防抖处理:用户停止输入300ms后再更新查询关键词 useEffect(() => { const timer = setTimeout(() => { setDebouncedQuery(query); }, 300); return () => clearTimeout(timer); }, [query]); const { data, status, error, hasNextPage, fetchNextPage } = useInfiniteQuery({ // 将防抖后的关键词加入queryKey,确保搜索变化时重置分页 queryKey: ["coupons", debouncedQuery], // 传递页码和搜索关键词给API请求函数 queryFn: ({ pageParam, queryKey }) => { const [_, searchQuery] = queryKey; return getPaginatedCoupons(pageParam, searchQuery); }, initialPageParam: 1, staleTime: Infinity, refetchOnWindowFocus: false, getNextPageParam: (lastPage, allPages) => { // 只有当前页有数据时才返回下一页页码 return lastPage?.length ? allPages.length + 1 : undefined; }, }); // 滚动到底部时加载下一页 useEffect(() => { if (inView && hasNextPage) { fetchNextPage(); } }, [inView, hasNextPage, fetchNextPage]); // 处理搜索栏的输入回调 const handleCouponsFilter = (searchTerm: string) => { setQuery(searchTerm); }; // 合并所有分页的数据 const coupons = data?.pages.flat() || []; return ( <div className="flex flex-col items-center justify-center mt-10"> <div className="flex w-3/4 items-center justify-center"> <SearchBar filter={handleCouponsFilter} /> </div> <div className="grid grid-rows-1 md:grid-cols-12 lg:grid-cols-12 p-0 md:p-0 lg:p-0 justify-center items-center mt-11 justify-items-center"> {coupons.map((coupon, index) => ( <div key={coupon.id || index} // 优先使用coupon的唯一ID作为key,避免索引key的问题 className="flex justify-center col-span-12 sm:col-span-12 md:col-span-4 w-full" > <CouponCard innerRef={index === coupons.length - 1 ? ref : undefined} card={coupon} /> </div> ))} </div> {/* 可选:加载状态提示 */} {status === "loading" && <div>加载中...</div>} {error && <div>加载失败:{error.message}</div>} </div> ); }; // 示例API请求函数:接收页码和搜索关键词 const getPaginatedCoupons = async (page: number, searchQuery: string) => { const response = await fetch(`/api/coupons?page=${page}&query=${encodeURIComponent(searchQuery)}`); if (!response.ok) throw new Error("请求失败"); return response.json(); }; export default CouponList;
额外说明
- Query Key的作用:当
debouncedQuery变化时,React Query会认为这是全新查询,自动清空之前的分页数据,重新从第一页获取结果。 - 防抖的必要性:防抖可以减少不必要的API请求,避免给服务器造成压力,同时提升用户体验。
- Key的优化:尽量使用数据的唯一ID作为
key,而非数组索引,避免React渲染时出现不必要的重排。
内容的提问来源于stack exchange,提问作者E.Bolandian
相关产品推荐
相关产品推荐

