如何为基于Jikan Anime API的React应用实现分页功能?
实现Jikan Anime API的React分页功能
核心思路
要实现分页,需要管理当前页码状态、动态传递页码给API请求,并利用API返回的分页数据控制按钮状态,具体步骤如下:
步骤1:添加页码状态管理
在组件顶部引入useState,用来存储当前页码:
import { useState } from 'react'; // ... 其他代码 ... const [currentPage, setCurrentPage] = useState(1);
步骤2:动态传递页码给API请求
把原来固定的1替换成currentPage,这样页码变化时会自动触发新的请求:
const { data: manga = [], isLoading, isFetching, error, } = useGetAnimeQuery(currentPage);
步骤3:解构分页控制字段
从API返回的pagination中提取关键字段,用来判断分页按钮的可用状态:
const { data: top_anime, pagination } = manga; const { current_page, last_page, has_next_page, has_prev_page } = pagination || {};
步骤4:实现分页按钮逻辑
编写页码切换的函数,同时做边界值限制(比如不能小于1,不能大于总页数):
const goToPrevPage = () => { if (has_prev_page) { setCurrentPage(prev => prev - 1); } }; const goToNextPage = () => { if (has_next_page) { setCurrentPage(prev => prev + 1); } };
步骤5:渲染分页控件
在预留的button容器中添加分页按钮和页码信息:
<div className="button text-yellow-500 flex items-center justify-center gap-4 mt-2 pb-2"> <button onClick={goToPrevPage} disabled={!has_prev_page || isFetching} className="px-4 py-2 bg-gray-700 rounded disabled:opacity-50 disabled:cursor-not-allowed" > 上一页 </button> <span>第 {current_page || 1} 页 / 共 {last_page || 1} 页</span> <button onClick={goToNextPage} disabled={!has_next_page || isFetching} className="px-4 py-2 bg-gray-700 rounded disabled:opacity-50 disabled:cursor-not-allowed" > 下一页 </button> </div>
修改后的完整组件代码
import { useState } from 'react'; import { useGetAnimeQuery } from './your-api-slice-path'; // 替换成你的API切片路径 import Spinner from './Spinner'; // 替换成你的Spinner组件路径 import TopAnime from './TopAnime'; // 替换成你的TopAnime组件路径 const TopAnimeList = () => { const [currentPage, setCurrentPage] = useState(1); const { data: manga = [], isLoading, isFetching, error, } = useGetAnimeQuery(currentPage); const { data: top_anime, pagination } = manga; const { current_page, last_page, has_next_page, has_prev_page } = pagination || {}; if (isLoading) { return <Spinner color_1="#141e30" color_2="#243b55" />; } if (isFetching) { return <Spinner color_1="#141e30" color_2="#243b55" />; } if (error) { console.log("ERROR =>", error.message); return <div className="text-white text-center py-8">加载失败,请稍后重试</div>; } const goToPrevPage = () => { if (has_prev_page) { setCurrentPage(prev => prev - 1); } }; const goToNextPage = () => { if (has_next_page) { setCurrentPage(prev => prev + 1); } }; return ( <section className="bg-gradient-to-r from-[#141e30] to-[#243b55]"> <div className="container font-poppins"> <div className="grid grid-cols-4 gap-3 place-items-center px-20 py-4"> {top_anime?.map((anime) => ( <TopAnime anime={anime} key={anime.mal_id} /> ))} </div> <div className="button text-yellow-500 flex items-center justify-center gap-4 mt-2 pb-4"> <button onClick={goToPrevPage} disabled={!has_prev_page || isFetching} className="px-4 py-2 bg-gray-700 rounded disabled:opacity-50 disabled:cursor-not-allowed" > 上一页 </button> <span>第 {current_page || 1} 页 / 共 {last_page || 1} 页</span> <button onClick={goToNextPage} disabled={!has_next_page || isFetching} className="px-4 py-2 bg-gray-700 rounded disabled:opacity-50 disabled:cursor-not-allowed" > 下一页 </button> </div> </div> </section> ); }; export default TopAnimeList;
关键细节说明
- 按钮添加
disabled属性,避免用户在无更多页或加载中重复点击 - 保留
isFetching状态的判断,切换页码时显示加载动画,提升用户体验 - 对
pagination做空值处理,避免API返回异常时出现报错
内容的提问来源于stack exchange,提问作者Haroon Islam
相关产品推荐
相关产品推荐

