React JS中如何排序合并API数据,实现表格按排名有序展示
问题描述
我从两个API获取数据:第一个API返回的数据是随机排序的,第二个API返回的数据是按排名组织的。将两个API的数据合并后,我能拿到API#2的POSITION、API#1的NAME以及API#2的POINTS,但合并后的数据是按照API#1的随机顺序排列的。
(原问题附带一张展示当前无序表格状态的截图)
请问如何通过sort().map调整代码,让表格中的结果按1、2、3这样的排名顺序展示?
原代码
import axios from "axios"; import React, { useState, useEffect } from "react"; import Pagination from "https://cdn.skypack.dev/rc-pagination@3.1.15"; const News = () => { const [playerName, setPlayerName] = useState([]); const [playerRank, setPlayerRank] = useState([]); const [player, setPlayer] = useState([]); const [perPage, setPerPage] = useState(10); const [size, setSize] = useState(perPage); const [current, setCurrent] = useState(1); const [players, setPlayers] = useState(); const fetchData = () => { const playerAPI = 'http://localhost:3008/api/players'; const playerRank = 'http://localhost:3008/api/highscore/players'; const getINFOPlayer = axios.get(playerAPI) const getPlayerRank = axios.get(playerRank) axios.all([getINFOPlayer, getPlayerRank]).then( axios.spread((...allData) => { const allDataPlayer = allData[0].data.players const getINFOPlayerRank = allData[1].data.players const newPlayer = allDataPlayer.map(name => { const pr = getINFOPlayerRank.find(rank => name.id === rank.id) return { id: name.id, name: name.name, status: name.status, position: pr?.position, score: pr?.score } // or simply do the following if the keys doesn't matter: return {...name, ...pr} }) setPlayerName(allDataPlayer) setPlayerRank(getINFOPlayerRank) console.log(newPlayer) setPlayer(newPlayer) }) ) } useEffect(() => { fetchData() }, []) const PerPageChange = (value) => { setSize(value); const newPerPage = Math.ceil(players.length / value); if (current > newPerPage) { setCurrent(newPerPage); } } const getData = (current, pageSize) => { // Normally you should get the data from the server return player?.slice((current - 1) * pageSize, current * pageSize); }; const sortData = getData && player?.sort((a, b) => a.position > b.position ? 1 : -1) const PaginationChange = (page, pageSize) => { setCurrent(page); setSize(pageSize) } const PrevNextArrow = (current, type, originalElement) => { if (type === 'prev') { return <button><i className="fa fa-angle-double-left"></i></button>; } if (type === 'next') { return <button><i className="fa fa-angle-double-right"></i></button>; } return originalElement; } return ( <> <div className="container-fluid mt-5 mb-5"> <div className="row justify-content-center"> <div className="col-md-10"> <div className="card"> <div className="card-body p-0"> <div className="table-filter-info"> <Pagination className="pagination-data" showTotal={(total, range) => `Showing ${range[0]}-${range[1]} of ${total}`} onChange={PaginationChange} total={player.length} current={current} pageSize={size} showSizeChanger={false} itemRender={PrevNextArrow} onShowSizeChange={PerPageChange} /> </div> <div className="table-responsive"> <table className="table table-text-small mb-0"> <thead className="thead-primary table-sorting"> <tr> <th>#</th> <th>Name</th> <th>Points</th> <th>Alliance</th> <th>Status</th> </tr> </thead> <tbody> {getData(current, size) .map((player) => { return ( <tr key={player.name}> <td>{player.position}</td> <td>{player.name}</td> <td>{player.score}</td> <td>{player.alliance}</td> <td>{player.status}</td> </tr> ); })} </tbody> </table> </div> <div className="table-filter-info"> <Pagination className="pagination-data" showTotal={(total, range) => `Showing ${range[0]}-${range[1]} of ${total}`} onChange={PaginationChange} total={player.length} current={current} pageSize={size} showSizeChanger={false} itemRender={PrevNextArrow} onShowSizeChange={PerPageChange} /> </div> </div> </div> </div> </div> </div> </> ) } export default News
解决方案
要让表格按排名顺序展示,核心是在合并数据后对数组按position字段排序,再将排序后的数组存入状态。原代码中定义的sortData变量未被实际调用,直接删除即可。
关键修改点
- 在生成
newPlayer数组后,立即调用sort()方法按position升序排序 - 删除未使用的
sortData变量
修改后的fetchData函数关键部分:
const newPlayer = allDataPlayer.map(name => { const pr = getINFOPlayerRank.find(rank => name.id === rank.id) return { id: name.id, name: name.name, status: name.status, position: pr?.position, score: pr?.score } }).sort((a, b) => (a.position || Infinity) - (b.position || Infinity));
使用(a.position || Infinity) - (b.position || Infinity)是为了兼容部分玩家没有position字段的情况,这类玩家会被排在最后。如果确认所有玩家都有position值,可以简化为a.position - b.position。
修改后的完整代码
import axios from "axios"; import React, { useState, useEffect } from "react"; import Pagination from "https://cdn.skypack.dev/rc-pagination@3.1.15"; const News = () => { const [playerName, setPlayerName] = useState([]); const [playerRank, setPlayerRank] = useState([]); const [player, setPlayer] = useState([]); const [perPage, setPerPage] = useState(10); const [size, setSize] = useState(perPage); const [current, setCurrent] = useState(1); const [players, setPlayers] = useState(); const fetchData = () => { const playerAPI = 'http://localhost:3008/api/players'; const playerRank = 'http://localhost:3008/api/highscore/players'; const getINFOPlayer = axios.get(playerAPI) const getPlayerRank = axios.get(playerRank) axios.all([getINFOPlayer, getPlayerRank]).then( axios.spread((...allData) => { const allDataPlayer = allData[0].data.players const getINFOPlayerRank = allData[1].data.players const newPlayer = allDataPlayer.map(name => { const pr = getINFOPlayerRank.find(rank => name.id === rank.id) return { id: name.id, name: name.name, status: name.status, position: pr?.position, score: pr?.score } }).sort((a, b) => (a.position || Infinity) - (b.position || Infinity)); setPlayerName(allDataPlayer) setPlayerRank(getINFOPlayerRank) console.log(newPlayer) setPlayer(newPlayer) }) ) } useEffect(() => { fetchData() }, []) const PerPageChange = (value) => { setSize(value); const newPerPage = Math.ceil(players.length / value); if (current > newPerPage) { setCurrent(newPerPage); } } const getData = (current, pageSize) => { // Normally you should get the data from the server return player?.slice((current - 1) * pageSize, current * pageSize); }; const PaginationChange = (page, pageSize) => { setCurrent(page); setSize(pageSize) } const PrevNextArrow = (current, type, originalElement) => { if (type === 'prev') { return <button><i className="fa fa-angle-double-left"></i></button>; } if (type === 'next') { return <button><i className="fa fa-angle-double-right"></i></button>; } return originalElement; } return ( <> <div className="container-fluid mt-5 mb-5"> <div className="row justify-content-center"> <div className="col-md-10"> <div className="card"> <div className="card-body p-0"> <div className="table-filter-info"> <Pagination className="pagination-data" showTotal={(total, range) => `Showing ${range[0]}-${range[1]} of ${total}`} onChange={PaginationChange} total={player.length} current={current} pageSize={size} showSizeChanger={false} itemRender={PrevNextArrow} onShowSizeChange={PerPageChange} /> </div> <div className="table-responsive"> <table className="table table-text-small mb-0"> <thead className="thead-primary table-sorting"> <tr> <th>#</th> <th>Name</th> <th>Points</th> <th>Alliance</th> <th>Status</th> </tr> </thead> <tbody> {getData(current, size) .map((player) => { return ( <tr key={player.name}> <td>{player.position}</td> <td>{player.name}</td> <td>{player.score}</td> <td>{player.alliance}</td> <td>{player.status}</td> </tr> ); })} </tbody> </table> </div> <div className="table-filter-info"> <Pagination className="pagination-data" showTotal={(total, range) => `Showing ${range[0]}-${range[1]} of ${total}`} onChange={PaginationChange} total={player.length} current={current} pageSize={size} showSizeChanger={false} itemRender={PrevNextArrow} onShowSizeChange={PerPageChange} /> </div> </div> </div> </div> </div> </div> </> ) } export default News
内容的提问来源于stack exchange,提问作者yandry santana
相关产品推荐
相关产品推荐

