React JS实现医生列表每页10条分页及按经验筛选功能开发问题
React医生列表分页+筛选功能实现方案
核心修改逻辑
- 新增
originalData状态存储全量接口返回数据,避免筛选后丢失原始数据 - 新增
selectedExp状态存储选中的经验筛选条件 - 新增
currentPage状态存储当前分页页码,默认值为1 - 固定每页展示条数为10,新增
pageSize常量 - 先根据筛选条件过滤全量数据,再对过滤后的数据做分页切片
- 给经验选择器、分页按钮绑定交互事件
完整修改后代码
import { useState, useEffect } from "react"; import { Link } from "react-router-dom"; import DocPic from "../img/doctor.png"; import InnerDetail from "./innerto_detail"; import axios from "axios"; export default function InnerSpecialities() { const [hasId, setHasId] = useState(false); const [detail, setDetail] = useState(false); // 新增原始全量数据存储 const [originalData, setOriginalData] = useState([]); // 新增经验筛选选中值 const [selectedExp, setSelectedExp] = useState("all"); // 新增分页相关状态 const [currentPage, setCurrentPage] = useState(1); const pageSize = 10; const inipath = window.location.pathname; const id_path = inipath.split("/cdoctor/details"); const path = inipath.split("/cdoctor/"); useEffect(() => { const pathname = window.location.pathname; const doctorId = pathname.split("/")[2]; console.log("this is the ", doctorId); console.log(id_path); const substring = "detiled"; console.log(inipath.includes(substring)); if (inipath.includes(substring) === true) { setDetail(true); } const config = { headers: { Authorization: `token ` + localStorage.getItem("token"), }, }; axios .get( "filter/?speciality=" + path[1], config ) .then((res) => { // 存储原始全量数据 setOriginalData(res.data); }); }, []); function OpenInner() { setDetail(true); } // 筛选逻辑:根据经验过滤数据 const filteredData = originalData.filter(item => { if(selectedExp === "all") return true; const exp = Number(item.experience); switch(selectedExp) { case "0-5": return exp >=0 && exp <5; case "5-10": return exp >=5 && exp <10; case "10-15": return exp >=10 && exp <15; case "15+": return exp >=15; default: return true; } }) // 分页逻辑:计算当前页展示的数据 const startIndex = (currentPage -1) * pageSize; const endIndex = startIndex + pageSize; const paginatedData = filteredData.slice(startIndex, endIndex); // 计算总页数 const totalPage = Math.ceil(filteredData.length / pageSize); // 筛选条件变更时重置页码为第一页 const handleExpChange = (e) => { setSelectedExp(e.target.value); setCurrentPage(1); } return ( <> {detail ? ( <InnerDetail /> ) : ( <div> <div> <div className="list-container" style={styles.options}> <div style={styles.inneropt}> <i style={styles.rotate} class="fa fa-exchange"></i>Sort By: <select style={styles.sel}> <option> Availability</option> <option> Nearby</option> <option> Price- Low to high</option> <option> Price- High to low</option> </select>{" "} </div> <div style={styles.inneropt}> Gender: <select style={styles.sel}> <option> Male</option> <option> Female</option> </select>{" "} </div> <div style={styles.inneropt}> Experience: {/* 绑定筛选值和变更事件 */} <select style={styles.sel} value={selectedExp} onChange={handleExpChange}> <option value="all">全部</option> <option value="0-5"> 0-5</option> <option value="5-10"> 5-10</option> <option value="10-15"> 10-15</option> <option value="15+"> 15+ </option> </select>{" "} </div> <div className="splang" style={styles.inneropt}> Language: <select style={styles.sel}> <option> English</option> <option> Malayaliam</option> <option> Tamil</option> <option> Kannada</option> </select>{" "} </div> </div> <div style={styles.container}> {/* 渲染当前页的筛选后数据 */} {paginatedData.map((personData, key) => { return ( <div style={styles.fbox} key={key}> <div style={styles.fitem}> <left> <img src={DocPic} alt="" /> <br /> <i className="fa fa-video-camera"></i> <br /> <small>Online</small> </left> <right style={{ textAlign: "left", marginLeft: "6px" }}> <strong> Dr {personData.firstname} {personData.lastname} </strong> <br /> <small> {" "} {personData.speciality} |{personData.experience} <small> years Exp.</small> </small> <br /> <strong>You Pay</strong> <br /> <strong>$600</strong> <br /> <small> {personData.qualification} {personData.location} </small> </right> </div> <Link to={{ pathname: "/doctor/detiled/" + personData.id, state: { id: personData.id, data: personData }, }} onClick={OpenInner} > <button style={styles.book}>Book Appointments</button> </Link> </div> ); })} </div> <div style={styles.pagination} className="pagination"> <div className="pager" style={{ margin: "auto", width: "30rem" }}> {/* 上一页按钮,第一页时禁用点击 */} <Link to="" onClick={(e) => { e.preventDefault(); if(currentPage >1) setCurrentPage(currentPage -1) }}> {" "} <i className="fa fa-angle-left"></i>{" "} </Link> {/* 动态渲染页码 */} {Array.from({length: totalPage}, (_,i) => i+1).map(page => ( <Link to="" key={page} style={{fontWeight: page === currentPage ? 'bold' : 'normal'}} onClick={(e) => { e.preventDefault(); setCurrentPage(page) }} > {page} </Link> ))} {/* 下一页按钮,最后一页时禁用点击 */} <Link to="" onClick={(e) => { e.preventDefault(); if(currentPage < totalPage) setCurrentPage(currentPage +1) }}> {" "} <i className="fa fa-angle-right"></i>{" "} </Link> </div> </div> </div> </div> )} </> ); }
注意事项
- 代码中默认医生数据的
experience字段是数字类型,若接口返回的是字符串,需要在过滤前先做类型转换 - 原有代码中冗余的
setdata逻辑已清理,统一用originalData存储全量接口数据 - 分页部分改为动态生成页码,不再固定显示7个页码,会根据筛选后的数据总条数自动计算总页数
内容的提问来源于stack exchange,提问作者vivek kn
相关产品推荐
相关产品推荐

