React-Table中能否通过两个API分别获取表头与数据字段?如何实现?
React-Table中能否通过两个API分别获取表头与数据字段?如何实现?
嘿,当然可以用两个独立API分别获取表头配置和表格数据啦!你的思路方向是对的,只是代码里有几个小细节需要调整,我帮你梳理一下~
先说说你代码里的几个问题
- 表头处理错误:你用
const headers = header.map(col => ({Header: col.ColumnName}))生成了一个对象数组,但React Table的Header属性需要的是字符串,不是对象。而且你把整个headers数组直接赋值给单个列的Header,这会导致表头渲染出[object Object]这类错误内容。 - useMemo依赖缺失:
columns的useMemo依赖项是空数组,这样当header和data加载完成后,columns不会重新计算,表格也不会更新。 - 缺少加载状态处理:API请求是异步的,在数据没返回前直接调用
map可能会触发报错。
调整后的实现方案
下面是修正后的完整代码,我会把关键调整点标注出来:
App.js 代码
import { useState, useEffect, useMemo } from 'react'; import ActiveTable from './ActiveTable'; function App() { const [data, setData] = useState([]); const [header, setHeader] = useState([]); const [isLoading, setIsLoading] = useState(true); // 新增加载状态,避免空数据报错 const fetchData = async () => { const response = await fetch('something'); const resData = await response.json(); setData(resData); }; const fetchHeader = async () => { const response = await fetch('anything'); const resData = await response.json(); setHeader(resData); }; useEffect(() => { const fetchAllData = async () => { // 用Promise.all同时发起两个API请求,提升加载效率 await Promise.all([fetchData(), fetchHeader()]); setIsLoading(false); // 所有数据加载完成后关闭加载状态 }; fetchAllData(); }, []); // 动态生成表格列:结合API返回的表头和固定列配置 const columns = useMemo(() => { // 把API返回的表头数据转换成React Table需要的列格式 const dynamicColumns = header.map(col => ({ Header: col.ColumnName, accessor: col.ColumnName, // 这里假设表头的ColumnName和数据里的字段名对应,不对应需要调整 })); // 固定列(比如你的图片列)可以单独定义,再和动态列合并 const fixedColumns = [ { Header: 'Logo', // 如果这个表头也需要从API获取,就从header数组里匹配对应字段 accessor: 'BusinessPartnerLogoUrl', Cell: (cell) => ( <img src={cell.row.original.BusinessPartnerLogoUrl} width={86} alt="Partner Logo" /> ) } ]; // 合并固定列和动态列,顺序可按需调整 return [...fixedColumns, ...dynamicColumns]; }, [header]); // 依赖header,表头变化时自动重新生成列配置 // 加载中显示提示 if (isLoading) { return <div>加载中,请稍候...</div>; } return ( <> <div className="container"> <div className="row mt-2"> <ActiveTable columns={columns} data={data}/> </div> </div> </> ); } export default App;
ActiveTable.js 代码
你的这部分代码基本没问题,只需要确保在数据未加载完成时不渲染表格即可(我们已经在App.js里处理了加载状态,所以这里可以保持原样):
// 保持你原来的代码即可,比如: import { Box } from '@mui/material'; // 假设你用了MUI组件 import TitleTable from './TitleTable'; import FilterButton from './FilterButton'; import ActionButton from './ActionButton'; import LegendaTable from './LegendaTable'; import { useTable } from 'react-table'; export default function ActiveTable({ columns, data }) { const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow, allColumns } = useTable({ columns, data }); return ( <Box> <TitleTable color="#009FB5">Aktivní smlouvy</TitleTable> <Table {...getTableProps()}> <TableHead> {headerGroups.map(headerGroup => ( <TableRow {...headerGroup.getHeaderGroupProps()}> {headerGroup.headers.map(column => ( <th {...column.getHeaderProps()}>{column.render("Header")}</th> ))} <th><FilterButton filterColumns={allColumns} /></th> </TableRow> ))} </TableHead> <tbody {...getTableBodyProps()}> {rows.map((row, i) => { prepareRow(row); return ( <TableRow {...row.getRowProps()} className="b-left-table tablerow-hover"> {row.cells.map(cell => ( <td {...cell.getCellProps()}>{cell.render("Cell")}</td> ))} <td><ActionButton/></td> </TableRow> ); })} </tbody> </Table> <LegendaTable/> </Box> ); }
额外说明
如果你的表头API返回的字段名和数据里的accessor不匹配(比如表头显示“合作伙伴Logo”,但数据字段是BusinessPartnerLogoUrl),可以让表头API返回包含accessor的结构,比如:
// 表头API返回示例 [ {"ColumnName": "合作伙伴Logo", "accessor": "BusinessPartnerLogoUrl"}, {"ColumnName": "产品名称", "accessor": "ProducText"} ]
然后在生成动态列时改成:
const dynamicColumns = header.map(col => ({ Header: col.ColumnName, accessor: col.accessor, }));
备注:内容来源于stack exchange,提问作者pathy
相关产品推荐
相关产品推荐

