React无限滚动组件首次加载正常,后续停滞于Loading状态求助
React无限滚动组件加载停滞问题排查与修复
问题现象
实现React无限滚动组件时,首次滚动至容器底部能正常加载新闻数据,但之后一直停留在“Loading...”状态,无法继续获取新的分页数据。
原代码片段
获取数据逻辑
const [latestNews, setLatestNews] = useState<any[]>([]); const [page, setPage] = useState<number>(1); const getLatestNews = async (page: number) => { let url = `https://api.nytimes.com/svc/search/v2/articlesearch.json?api-key=${API_KEY}&page=${page}`; const response = await fetch(url); const data = await response.json(); setLatestNews(data.response.docs); setPage(page + 1); }
无限滚动组件
<InfiniteScroll dataLength={latestNews.length} next={() => getLatestNews(page)} hasMore={true} loader={<h4>Loading...</h4>} scrollableTarget="scrollableDiv" > { latestNews.map((article, index) => ( <div className="latest-news-article flex flex-col gap-3 mb-4" key={index}> <p className="latest-news-article-date"> {article.pub_date.slice(11, 16)} </p> <h1> {article.headline.main} </h1> </div> )) } </InfiniteScroll>
问题原因
- 数据覆盖而非追加:
setLatestNews(data.response.docs)直接替换了原数组,导致dataLength(即latestNews.length)在首次加载后没有增长,InfiniteScroll组件判断没有新数据加载完成,不会再次触发next回调。 - 闭包导致page值固化:
next={() => getLatestNews(page)}中的page是组件首次渲染时的闭包值,每次触发next都是传入page=1,后续请求始终获取第一页数据,无法真正翻页。
修复方案
1. 修改数据更新逻辑,追加新数据
将直接替换数组改为追加新数据,确保dataLength能正确反映列表总长度:
setLatestNews(prev => [...prev, ...data.response.docs]);
2. 解决page闭包问题
直接在getLatestNews中读取当前page状态,避免闭包带来的旧值问题:
const getLatestNews = async () => { const currentPage = page; let url = `https://api.nytimes.com/svc/search/v2/articlesearch.json?api-key=${API_KEY}&page=${currentPage}`; const response = await fetch(url); const data = await response.json(); setLatestNews(prev => [...prev, ...data.response.docs]); setPage(prev => prev + 1); } // 对应InfiniteScroll的next修改为: next={getLatestNews}
额外优化:添加加载状态与hasMore判断
避免重复请求和无效无限加载,可补充状态控制:
const [isLoading, setIsLoading] = useState(false); const [hasMore, setHasMore] = useState(true); const getLatestNews = async () => { if (isLoading) return; setIsLoading(true); try { const currentPage = page; let url = `https://api.nytimes.com/svc/search/v2/articlesearch.json?api-key=${API_KEY}&page=${currentPage}`; const response = await fetch(url); const data = await response.json(); const newArticles = data.response.docs; setLatestNews(prev => [...prev, ...newArticles]); // 根据返回数据长度判断是否还有更多内容 setHasMore(newArticles.length > 0); setPage(prev => prev + 1); } catch (error) { console.error('加载新闻失败:', error); } finally { setIsLoading(false); } } // 对应InfiniteScroll组件: <InfiniteScroll dataLength={latestNews.length} next={getLatestNews} hasMore={hasMore} loader={<h4>Loading...</h4>} scrollableTarget="scrollableDiv" > {/* 渲染列表 */} </InfiniteScroll>
内容的提问来源于stack exchange,提问作者Renato
相关产品推荐
相关产品推荐

