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

使用REST API数据时React可排序表格为空的问题排查

问题:REST API获取数据后启用排序逻辑,表格无数据展示

我正在开发第一个React项目,实现了一个可排序表格。用本地JSON文件填充数据时,排序功能正常;但切换为从REST API获取数据后,禁用排序逻辑表格能正常渲染,启用排序后表格完全没有数据。

相关代码

App组件

import HardwaresTable from "./tc/HardwaresTable";

const App = () => {
    return (
        <div className="table_container">
            <HardwaresTable/>
        </div>
    );
};

export default App;

HardwaresTable组件

import Table from "../components/Table";
import testHardwares from "../test/hardwares.json";
import TableHead from "../components/TableHead";
import TableBody from "../components/TableBody";
import {useSortableTable} from "../util/useSortableTable";
import {useEffect, useState} from "react";
import axios from "axios";

const HardwaresTable = () => {
    const hardwaresColumns = [
        { label: "ID", accessor: "id", sortable: true, sortByOrder: "asc", type: "int" },
        { label: "Hardware Name", accessor: "hardwareName", sortable: false, type: "string" },
        { label: "Display Name", accessor: "displayName", sortable: true, type: "string" },
        { label: "Hardware Make", accessor: "hardwareMake", sortable: true, type: "enum" },
        { label: "Hardware Type", accessor: "hardwareType", sortable: true, type: "enum" },
        { label: "Multiplier", accessor: "multiplier", sortable: true, type: "double" },
        { label: "Average PPD", accessor: "averagePpd", sortable: true, type: "int" },
    ];

    const [loadingData, setLoadingData] = useState(true);
    const [hardwares, setHardwares] = useState([]);

    useEffect(() => {
        async function getData() {
            await axios
                .get("https://internal.axihub.ca/folding/hardware")
                .then((response) => {
                    // console.log(response.data);
                    setHardwares(response.data);
                });
        }
        if (loadingData) {
            getData()
                .then(r => {
                    setLoadingData(false)
                });
        }
    }, []);

    //// 'hardwares' has all content correctly here ////
    const [tableData, handleSorting] = useSortableTable(hardwares, hardwaresColumns);
    //// After calling 'useSortableTable()', 'tableData' is empty ////

    return (
        <table className="table">
            <caption>Hardwares on the system</caption>
            <TableHead columns={hardwaresColumns} handleSorting={handleSorting} />
            {loadingData ? "" : <TableBody tableData={tableData} columns={hardwaresColumns} />}
        </table>
    );
};

export default HardwaresTable;

useSortableTable自定义Hook

import {useState} from "react";

function getDefaultSorting(defaultTableData: any[], columns: any) {
    return [...defaultTableData].sort((a, b) => {
        const filterColumn = columns.filter((column: { sortByOrder: boolean; }) => column.sortByOrder);

        // Merge all array objects into single object and extract accessor and sortByOrder keys
        let {accessor = "id", sortByOrder = "asc"} = Object.assign(
            {},
            ...filterColumn
        );

        if (a[accessor] === null) return 1;
        if (b[accessor] === null) return -1;
        if (a[accessor] === null && b[accessor] === null) return 0;

        const ascending = a[accessor]
            .toString()
            .localeCompare(b[accessor].toString(), "en", {
                numeric: true,
            });

        return sortByOrder === "asc" ? ascending : -ascending;
    });
}

export const useSortableTable = (data: any, columns: any) => {
    const [tableData, setTableData] = useState(getDefaultSorting(data, columns));
    console.log(tableData);

    const handleSorting = (sortField: any, sortOrder: string) => {
        if (sortField) {
            const sorted = [...tableData].sort((a, b) => {
                if (a[sortField] === null) return 1;
                if (b[sortField] === null) return -1;
                if (a[sortField] === null && b[sortField] === null) return 0;
                return (
                    a[sortField]
                        .toString()
                        .localeCompare(b[sortField].toString(), "en", {
                            numeric: true,
                        }) * (sortOrder === "asc" ? 1 : -1)
                );
            });
            setTableData(sorted);
        }
    };

    return [tableData, handleSorting];
};

排查方向及解决方案建议

  1. Hook初始化数据时机问题

    • useSortableTable内部的useState仅在组件挂载时执行一次初始化,此时API数据尚未返回,hardwares是空数组,导致tableData初始化为空。后续hardwares更新时,Hook不会重新计算排序后的数据。
    • 解决:在useSortableTable中添加useEffect监听传入的data变化,当数据更新时重新执行排序并更新tableData:
      export const useSortableTable = (data: any, columns: any) => {
          const [tableData, setTableData] = useState(getDefaultSorting(data, columns));
          
          // 监听数据变化,重新排序
          useEffect(() => {
              setTableData(getDefaultSorting(data, columns));
          }, [data, columns]);
      
          // ... 原有handleSorting逻辑
      };
      
  2. 数据类型与排序逻辑冲突

    • API返回的数据可能存在null、undefined或非字符串/数字类型的字段,调用toString()时会报错,导致排序失败返回空数组。
    • 排查:在getDefaultSorting函数中添加日志,打印对比字段的实际值和类型:
      console.log(`Comparing ${a[accessor]} (type: ${typeof a[accessor]}) vs ${b[accessor]} (type: ${typeof b[accessor]})`);
      
    • 优化:给toString()调用添加兜底,避免报错:
      const ascending = String(a[accessor])
          .localeCompare(String(b[accessor]), "en", { numeric: true });
      
  3. 初始列筛选逻辑错误

    • columns.filter((column: { sortByOrder: boolean; }) => column.sortByOrder)中,sortByOrder是字符串("asc")而非布尔值,导致筛选结果为空,进而使用默认accessor为"id"。若API返回数据中id字段不存在或类型异常,会导致排序失败。
    • 解决:修正筛选条件为判断sortByOrder是否存在:
      const filterColumn = columns.filter(column => column.sortByOrder !== undefined);
      

内容的提问来源于stack exchange,提问作者zodac

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 00:27:13