React集成SWAPI实现无限滚动问题:无法加载更多页面求助
问题分析与修改方案
你的代码存在几个核心问题导致无法加载更多数据:
fetchPeople函数的问题:- 提前定义的
peopleApi会在组件每次渲染时创建,但它依赖的page变量不会动态更新,而且fetchPeople每次调用都会用初始的page=1的请求。 fetchPeople直接用setPeople(transformPeople)覆盖现有数据,没有实现追加逻辑。fetchPeople没有返回API响应里的next分页链接,导致getMorePeople无法获取下一页地址。
- 提前定义的
getMorePeople函数的逻辑错误:- 调用
fetchPeople(people)时,fetchPeople并不接受参数,也不会返回{next, results},导致解构报错。 - 递归调用的方式不适合React组件,应该通过更新state来触发新的请求,而不是递归返回数据。
- 点击按钮时,
getMorePeople没有正确关联组件的page或next状态。
- 调用
useEffect依赖缺失:
初始的useEffect只执行一次,没有监听page或next的变化,无法触发新的请求。
修改后的完整代码
import { useEffect, useState } from "react"; import axios from "axios"; const swapi = axios.create({ baseURL: "https://swapi.dev/api/" }); const InfiniteScroll = () => { const [people, setPeople] = useState([]); const [nextPageUrl, setNextPageUrl] = useState("people/?page=1"); const [isLoading, setIsLoading] = useState(false); // 封装通用的获取人物数据函数,接收请求地址,返回处理后的数据和下一页地址 const fetchPeople = async (url) => { setIsLoading(true); try { const response = await swapi.get(url); const transformedPeople = response.data.results.map(person => ({ name: person.name, height: person.height, hair_color: person.hair_color, skin_color: person.skin_color, birth_year: person.birth_year })); return { data: transformedPeople, next: response.data.next }; } catch (err) { console.error("获取数据失败:", err); return { data: [], next: null }; } finally { setIsLoading(false); } }; // 初始加载第一页数据 useEffect(() => { const loadInitialData = async () => { const { data, next } = await fetchPeople(nextPageUrl); setPeople(data); setNextPageUrl(next); }; loadInitialData(); }, []); // 加载更多数据的函数 const getMorePeople = async () => { if (!nextPageUrl || isLoading) return; // 没有下一页或正在加载时不触发请求 const { data, next } = await fetchPeople(nextPageUrl); setPeople(prevPeople => [...prevPeople, ...data]); // 追加新数据 setNextPageUrl(next); }; return ( <> <div> {people.map((onePerson) => ( <div key={onePerson.name}> <p>{onePerson.name}</p> <p>Height: {onePerson.height}</p> <p>Hair color: {onePerson.hair_color}</p> <p>Skin color: {onePerson.skin_color}</p> <p>Birth year: {onePerson.birth_year}</p> </div> ))} <button onClick={getMorePeople} disabled={!nextPageUrl || isLoading} > {isLoading ? "加载中..." : nextPageUrl ? "加载更多" : "没有更多数据"} </button> </div> </> ); }; export default InfiniteScroll;
关键改动说明
- 用
nextPageUrl代替page状态:直接存储API返回的next链接,避免手动计算页码,适配SWAPI的分页机制。 - 重构
fetchPeople:让它接收请求地址,返回处理后的数据和下一页链接,同时添加加载状态和错误处理。 - 修改数据更新逻辑:使用
setPeople(prevPeople => [...prevPeople, ...data])来追加新数据,而不是覆盖原有数据。 - 修正
getMorePeople:直接利用nextPageUrl发起请求,更新state,去掉错误的递归逻辑,同时添加加载状态的判断,防止重复请求。 - 优化按钮状态:根据是否有下一页和加载状态,禁用按钮并显示对应文本,提升用户体验。
内容的提问来源于stack exchange,提问作者Dominika Es
相关产品推荐
相关产品推荐

