ReactJS提取嵌套数组数据渲染表格的问题与实现方案
现有代码的核心问题
你当前的实现有5个明确错误,导致无法渲染出预期效果:
- 行结构逻辑错误:你在外层遍历每个请假原因组时,直接为每个组生成1个
<tr>行标签,但预期效果是每个请假人对应1行,同个请假原因下的多个人需要生成多个独立行,把多个人的单元格塞到同一行里完全不符合表格结构规则。 - JSX语法错误:内层的
data.list.map是JS表达式,在JSX中必须包裹在{}中才能执行,你写的这部分代码不会被React解析,直接会报语法错误。 - 缺少返回值:内层map的回调函数用
{}包裹了逻辑,但没有显式return要渲染的<td>节点,这部分不会生成任何DOM内容。 - 缺少必填key属性:React列表渲染时,循环生成的根节点必须设置唯一key值,否则会出现渲染性能下降、组件状态错乱的问题。
- 表格结构缺失:没有编写
<table>、<thead>、<tbody>等基础表格容器标签,零散的<tr>/<td>会被浏览器自动修正解析,导致结构完全混乱。
正确实现方案
双层遍历的思路本身是可行的,只需要调整遍历的层级逻辑:在外层遍历请假原因组时,不要直接生成行,而是在内层遍历组内的请假人时,为每个请假人生成独立的<tr>,同时携带当前组的reason字段即可。
写法1:先拍平数据再渲染(逻辑更清晰)
用flatMap把嵌套的接口数据提前转换成一维的行数据数组,每行对应一个请假人,之后直接遍历一维数组渲染即可,代码可读性更高:
import { FunctionComponent } from 'react'; // 接口返回的原始数据 const myArray = [ { reason: 'vacation', list: [ { name: 'John Doe', startsAt: '2022-05-19', endsAt: '2022-06-01' }, { name: 'Jenifer Doe', startsAt: '2022-06-10', endsAt: '2022-06-15' } ], }, { reason: 'sick', list: [{ name: 'Susan', startsAt: '2022-05-20', endsAt: '2022-05-21' }] } ]; export const MyComponent: FunctionComponent = () => { // 拍平为一维行数据:每条记录对应表格一行 const tableRows = myArray.flatMap(group => group.list.map(person => ({ name: person.name, createdAt: person.startsAt, canceledAt: person.endsAt, reason: group.reason })) ); return ( <table> <thead> <tr> <th>Name</th> <th>Created at</th> <th>Canceled at</th> <th>Reason</th> </tr> </thead> <tbody> {tableRows.map((row, index) => ( // 业务场景下如果有唯一用户id/请假单id,优先用id作为key <tr key={`${row.name}-${row.createdAt}-${index}`}> <td>{row.name}</td> <td>{row.createdAt}</td> <td>{row.canceledAt}</td> <td>{row.reason}</td> </tr> ))} </tbody> </table> ); };
写法2:JSX内直接嵌套遍历
如果不想提前处理数据,也可以直接在JSX结构中嵌套遍历,注意外层组需要用Fragment包裹多个<tr>,同时给Fragment设置key即可:
import { Fragment, FunctionComponent } from 'react'; const myArray = [/* 同上原始数据 */]; export const MyComponent: FunctionComponent = () => { return ( <table> <thead> <tr> <th>Name</th> <th>Created at</th> <th>Canceled at</th> <th>Reason</th> </tr> </thead> <tbody> {myArray.map(group => ( <Fragment key={group.reason}> {group.list.map(person => ( <tr key={`${person.name}-${person.startsAt}`}> <td>{person.name}</td> <td>{person.startsAt}</td> <td>{person.endsAt}</td> <td>{group.reason}</td> </tr> ))} </Fragment> ))} </tbody> </table> ); };
两种写法最终渲染的表格结构完全匹配你给出的预期效果。
内容的提问来源于stack exchange,提问作者PandaMastr
相关产品推荐
相关产品推荐

