React Infinite Scroll问题:fetchNextPage未触发,无法加载更多数据
React无限滚动不触发加载的问题修复
你的代码存在几个关键问题导致fetchNextPage未被调用,以下是具体修复方案:
1. 滚动容器无触发条件
react-infinite-scroll-component需要内容高度超过可视区域才会触发next回调。如果当前渲染的10条内容不足以撑满页面,不会出现滚动条,组件也就不会触发加载。
- 修复:给外层容器添加最小高度样式,确保页面可滚动:
<div className="min-h-screen"> {/* 原内容 */} </div>
2. 状态更新的闭包陷阱
fetchNextPage中直接使用firstId、lastId和pages更新状态时,会因为闭包问题拿到旧的状态值,导致分页逻辑错误。
- 修复:使用函数式状态更新获取最新状态:
const fetchNextPage = () => { const result = items.slice(firstId, lastId); setPages(prevPages => [...prevPages, ...result]); if (result.length === 0 || result.length < 10) { setHasMore(false); } setFirstId(prev => prev + 10); setLastId(prev => prev + 10); };
3. 分类切换时未重置分页状态
当categoryId变化重新拉取数据时,firstId、lastId和hasMore没有重置,导致分页逻辑混乱,同时原代码中依赖items的useEffect会覆盖pages但未同步更新分页游标。
- 修复:合并分页初始化逻辑到数据加载的
useEffect中,去掉多余的useEffect:useEffect(() => { setLoading(true); // 重置所有分页状态 setFirstId(10); setLastId(20); setHasMore(true); const fetchData = async () => { const data = categoryId ? await client.fetch(searchQuery(categoryId)) : await client.fetch(feedQuery); setItems(data); setPages(data.slice(0, 10)); setLoading(false); if (data.length <= 10) setHasMore(false); }; fetchData(); }, [categoryId]);
4. 优化InfiniteScroll配置
确保dataLength正确反映已加载条目数,同时调整endMessage的位置(它应该是InfiniteScroll的props,而非Spinner的属性):
<InfiniteScroll dataLength={pages?.length} next={fetchNextPage} hasMore={hasMore} loader={<Spinner message="Searching for items..." />} endMessage={ <p className="align-center font-extrabold">End of list.</p> } > {/* 内容 */} </InfiniteScroll>
修改后的完整代码
import React, { useState, useEffect } from "react"; import { useParams } from "react-router-dom"; import { client } from "../client"; import MasonryLayout from "./MasonryLayout"; import Spinner from "./Spinner"; import { feedQuery, searchQuery } from "../utils/data"; import InfiniteScroll from "react-infinite-scroll-component"; const Feed = () => { const [loading, setLoading] = useState(false); const { categoryId } = useParams(); const [items, setItems] = useState(null); const [pages, setPages] = useState([]); const [firstId, setFirstId] = useState(10); const [lastId, setLastId] = useState(20); const [hasMore, setHasMore] = useState(true); useEffect(() => { setLoading(true); setFirstId(10); setLastId(20); setHasMore(true); const fetchData = async () => { const data = categoryId ? await client.fetch(searchQuery(categoryId)) : await client.fetch(feedQuery); setItems(data); setPages(data.slice(0, 10)); setLoading(false); if (data.length <= 10) setHasMore(false); }; fetchData(); }, [categoryId]); const fetchNextPage = () => { const result = items.slice(firstId, lastId); setPages(prevPages => [...prevPages, ...result]); if (result.length === 0 || result.length < 10) { setHasMore(false); } setFirstId(prev => prev + 10); setLastId(prev => prev + 10); }; if (loading) return <Spinner message="Searching for items...!" />; if (!pages?.length) return <h2>No results available.</h2>; return ( <InfiniteScroll dataLength={pages?.length} next={fetchNextPage} hasMore={hasMore} loader={<Spinner message="Searching for items..." />} endMessage={ <p className="align-center font-extrabold">End of list.</p> } > <div className="min-h-screen"> <div className="mt-4 mb-4 w-full rounded overflow-hidden shadow-lg bg-slate-50 pl-2 pr-2 pt-4 pb-4"> <p>Some information about this … </p> </div> {pages && <MasonryLayout items={pages} />} </div> </InfiniteScroll> ); }; export default Feed;
内容的提问来源于stack exchange,提问作者user2647092
相关产品推荐
相关产品推荐

