You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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变量未被实际调用,直接删除即可。

关键修改点

  1. 在生成newPlayer数组后,立即调用sort()方法按position升序排序
  2. 删除未使用的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 04:25:18