React实现带搜索的无限滚动 清空搜索后分页失效处理
问题根因
分页失效的核心问题有3个:
- 搜索关键词变更时,仅重新拉取了第一页数据,没有同步重置
page页码状态和hasMore加载标记:搜索过程中不断累加的页码,会在清空搜索后直接作为请求参数传给接口,导致跳过正常的分页顺序,拿不到对应数据 - 分页加载逻辑直接取闭包中缓存的
page、data旧值,快速滚动或者状态快速变更时容易出现数据拼接错误、页码跳变 - 原代码中JSX部分漏写了
data.map的数据源变量,会直接导致渲染报错(属于笔误)
修复方案
- 在监听
search变化的副作用逻辑中,每次重新拉取第一页数据后,将page重置为1(因为第一页page=0已经加载完成,下一次触发加载要请求第1页),同时将hasMore重置为true,保证后续滚动可以正常触发加载 - 调整分页请求和状态更新逻辑,用React状态的函数式更新获取最新的状态值,避免闭包旧值导致的逻辑错误
- 补全JSX中缺失的
data数据源遍历逻辑,可选优化:对搜索参数做URL编码,避免特殊字符导致请求异常
修复后完整代码
useEffect(() => { const getData = async () => { const { data } = await axios( search ? `http://localhost:3003/api/product/pagination?page=0&search=${encodeURIComponent(search)}` : `http://localhost:3003/api/product/pagination?page=0` ); setData(data.posts); // 重置分页状态 setPage(1); setHasMore(true); }; if (search.length === 0 || search.length > 2) { getData(); } }, [search]); const fetchPosts = async (currentPage, searchKey) => { const { data } = await axios( `http://localhost:3003/api/product/pagination?page=${currentPage}&search=${encodeURIComponent(searchKey)}` ); return data.posts; }; const fetchData = async () => { setPage(prevPage => { // 用最新的页码值发起请求 fetchPosts(prevPage, search).then(postsFromServer => { setData(prevData => [...prevData, ...postsFromServer]); if (postsFromServer.length === 0 || postsFromServer.length < 4) { setHasMore(false); } }); return prevPage + 1; }); }; return ( <> <InfiniteScroll dataLength={data.length} next={fetchData} hasMore={hasMore} loader={<h4>Loading...</h4>} > <Container> {data.map((item) => { const { _id, kampaniyaName, owner, aboutProduct, startDate, endDate, price, category, image, } = item; return ( <div key={item._id}> <Card _id={_id} name={kampaniyaName} company={owner} about={aboutProduct} date={timeLeft(startDate, endDate)} price={price} category={category} image={image} data={item} /> </div> ); })} </Container> </InfiniteScroll> </> ); }; export default Home;
额外优化建议
- 可以加一个loading状态锁,避免滚动到临界点时重复触发相同页码的请求
- 搜索输入建议加防抖,减少输入过程中无效的接口请求
内容的提问来源于stack exchange,提问作者Mastan Abdulkhaligli
相关产品推荐
相关产品推荐

