React-Table结合Axios渲染报错data.forEach is not a function
问题根因
react-table 的 useTable Hook 要求传入的 data 参数必须是对象数组,每一个数组元素对应表格的一行数据。你遇到的报错和无限加载问题本质都是数据格式不匹配:
- 教程里使用的TVMaze搜索接口返回值本身就是数组结构,直接传给
setData完全符合react-table的入参要求 - 你调用的MyAnimeList单条动漫详情接口返回的是单个对象,不是数组。你觉得两个接口返回结构“看起来一致”是视觉误差:TVMaze接口返回值最外层是
[]包裹的数组,MAL单条详情接口最外层是{}包裹的单个对象,结构完全不同。useTable内部会调用data.forEach遍历数组行数据,传入对象时自然会抛出data.forEach is not a function的错误 - 你之前添加的
return !data.length ? (Loading..)加载判断失效,是因为普通JavaScript对象没有length属性,取对象的length会得到undefined,!undefined永远为真,所以页面会一直卡在加载状态,不会渲染任何内容。
另外你在请求头里添加的Access-Control-Allow-Origin: *是无效配置:这个头是服务端返回给浏览器的响应头,前端发起请求时主动携带这个头没有任何作用,反而可能触发CORS预检请求异常,建议直接删除。
修复方案
1. 修正存入state的数据格式
拿到接口返回的单个对象后,把它包成数组再存入data state,修改App.js里的请求逻辑:
useEffect(() => { axios .get('https://cors-anywhere.herokuapp.com/https://api.myanimelist.net/v2/anime/30230?fields=id,title,genres',{ headers: { 'X-MAL-CLIENT-ID' : '你的实际CLIENT ID' }, responseType: 'json' }) .then(result => { // 单条对象包成数组再存入state,符合react-table的入参要求 setData([result.data]) }) }, []);
如果你后续要调用MAL的动漫列表接口(比如动漫排行、季度新番这类返回多条数据的接口),接口返回的data里会嵌套data数组字段,这时候直接取result.data.data存入state即可,不需要额外包数组。
2. 修正加载状态判断逻辑
不要只用!data.length做判断,要先校验data是否为合规数组,避免单个对象导致判断逻辑失效:
// 在App组件的return部分前置判断 if (!Array.isArray(data) || data.length === 0) { return <div>加载中...</div> } return ( <div className="App"> <Table columns={columns} data={data} /> </div> );
如果后续要渲染genres这类数组类型的字段,只需要在columns配置里新增对应accessor,自定义Cell渲染逻辑即可,示例配置:
const columns = useMemo( () => [ { Header: "TITLE", accessor: "title" }, { Header: "GENRES", accessor: "genres", Cell: ({ value }) => value.map(genre => genre.name).join(', ') } ], [] );
验证方法
修改后打开控制台打印data,确认data是长度为1的数组,数组元素是接口返回的动漫详情对象,useTable就可以正常遍历渲染行数据,不会再抛出forEach相关报错,加载状态也会在接口返回后正常消失,渲染出表格内容。
内容的提问来源于stack exchange,提问作者Tarranon
相关产品推荐
相关产品推荐

