使用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]; };
排查方向及解决方案建议
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逻辑 };
数据类型与排序逻辑冲突
- 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 });
- API返回的数据可能存在
初始列筛选逻辑错误
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
相关产品推荐
相关产品推荐

