如何用Axios、useState和useEffect实现多页面数据获取及加载更多
实现Rick and Morty API的加载更多功能
问题分析
你的现有代码仅能获取单页数据,要实现加载更多并存储全量数据用于后续筛选,需要补充下一页链接跟踪、数据追加逻辑,同时调整状态的初始类型(原代码用对象存储数组数据不合适)。
修改后完整代码
import { useState, useEffect } from 'react'; import axios from 'axios'; function CharacterList() { // 存储所有已加载的角色数据(数组类型,初始为空数组) const [characters, setCharacters] = useState([]); // 用于筛选后的展示数据 const [filtered, setFiltered] = useState([]); // 存储下一页的API链接(从接口返回的info.next字段获取) const [nextPageUrl, setNextPageUrl] = useState(null); // 加载状态,防止重复点击加载按钮 const [isLoading, setIsLoading] = useState(false); const baseUrl = 'https://rickandmortyapi.com/api/character/'; // 初始加载第一页数据 useEffect(() => { fetchPage(baseUrl); }, []); // 封装通用的分页请求函数 const fetchPage = async (url) => { setIsLoading(true); try { const res = await axios.get(url); // 将新页数据追加到已有数据末尾 setCharacters(prev => [...prev, ...res.data.results]); // 同步更新筛选数据(无筛选条件时直接复用全量数据) setFiltered(prev => [...prev, ...res.data.results]); // 保存下一页链接,无更多数据时为null setNextPageUrl(res.data.info.next); } catch (error) { console.error('加载数据失败:', error); } finally { setIsLoading(false); } }; // 加载更多按钮点击事件 const handleLoadMore = () => { if (nextPageUrl && !isLoading) { fetchPage(nextPageUrl); } }; return ( <div> {/* 角色列表展示 */} <div className="character-list"> {filtered.map(character => ( <div key={character.id} className="character-card"> <img src={character.image} alt={character.name} /> <h3>{character.name}</h3> <p>状态: {character.status}</p> </div> ))} </div> {/* 加载更多按钮:无下一页或加载中时禁用 */} <button onClick={handleLoadMore} disabled={!nextPageUrl || isLoading} style={{ marginTop: '20px', padding: '10px 20px' }} > {isLoading ? '加载中...' : '加载更多'} </button> </div> ); } export default CharacterList;
关键修改点说明
- 状态调整:
- 将
characters和filtered的初始值改为空数组,匹配接口返回的results数组类型 - 新增
nextPageUrl跟踪下一页接口地址,无需手动计算页码(API返回的info.next直接提供下一页链接) - 新增
isLoading状态避免重复发起请求
- 将
- 数据追加逻辑:使用
setCharacters(prev => [...prev, ...newData])将新页数据追加到已有数据后,保留全量数据用于后续筛选 - 通用请求封装:把分页请求封装成
fetchPage函数,初始加载和加载更多逻辑复用,减少冗余代码 - 按钮交互优化:根据
nextPageUrl和isLoading状态禁用按钮,避免无效点击
后续筛选扩展示例
当需要添加筛选功能时,只需基于全量的characters数据过滤,更新filtered状态即可,比如按名字筛选:
// 按名字筛选示例 const handleFilterByName = (keyword) => { const filteredData = characters.filter(character => character.name.toLowerCase().includes(keyword.toLowerCase()) ); setFiltered(filteredData); };
内容的提问来源于stack exchange,提问作者BORA PERTEV
相关产品推荐
相关产品推荐

