如何通用生成MUI DataGrid动态Rows(非硬编码字段)
问题描述
以下是MUI DataGrid文档v7.10.0中的示例:
const tempColumns: GridColDef[] = [ { field: "id", headerName: "ID", width: 90 }, { field: "firstName", headerName: "First name", width: 150, }, { field: "lastName", headerName: "Last name", width: 150, }, ]; const rows = [ { id: 1, lastName: 'Snow', firstName: 'Jon' }, { id: 2, lastName: 'Lannister', firstName: 'Cersei' }, { id: 3, lastName: 'Lannister', firstName: 'Jaime' }, ];
上述示例中,rows是通过硬编码值和字段初始化的。
现在Columns将动态生成(支持用户自定义),Columns的定义数据来自API接口,Rows的数据来自一个或多个API接口。
如何通过获取API数据,拼接出可传入DataGrid组件rows属性的对象数组?
我猜想可以通过解析Columns数组获取所用字段名称,但具体该如何操作?
我不能直接采用以下写法(因为我不知道"field"和"field2"的存在,且字段可能多达上百个,这种方式不可行):
rows.push({ id: 1, field: "some value", field2: "some value" })
是否存在通用的实现方式?
解决方案
核心思路
通过解析API返回的columns数组提取所有字段名,再将API返回的原始数据映射为DataGrid要求的结构——确保每一行对象只包含columns中定义的字段,同时保证行唯一标识(默认是id字段)存在。
具体实现步骤
- 提取Columns中的字段列表
先从API获取columns数据,提取所有field字段,同时确认行唯一标识字段(默认id)存在,若不存在需手动处理或配置DataGrid的getRowId属性指定其他唯一字段。
// 从API获取动态列配置 const apiColumns: GridColDef[] = await fetch('/api/columns').then(res => res.json()); // 提取所有需要的字段名 const requiredFields = apiColumns.map(col => col.field); // 确保行唯一标识存在(DataGrid强制要求) if (!requiredFields.includes('id')) { // 若API未返回id字段,可手动添加,或后续配置getRowId requiredFields.push('id'); }
- 映射原始数据为DataGrid可用格式
遍历API返回的原始数据,仅保留requiredFields中定义的字段,生成符合要求的行对象。如果数据来自多个API,先通过唯一标识合并再映射。
// 从API获取原始行数据 const rawRows = await fetch('/api/rows').then(res => res.json()); // 映射为DataGrid兼容的行数组 const dataGridRows = rawRows.map(rawRow => { const row: Record<string, any> = {}; requiredFields.forEach(field => { // 从原始数据取对应字段值,无值则设为null避免渲染异常 row[field] = rawRow[field] ?? null; }); return row; });
- 多API数据合并(可选)
若行数据来自多个API,可通过唯一标识(如id)先合并数据:
// 从两个API获取数据 const basicRows = await fetch('/api/basic-rows').then(res => res.json()); const extendedRows = await fetch('/api/extended-rows').then(res => res.json()); // 将扩展数据转为Map,方便快速查找 const extendedDataMap = new Map(extendedRows.map(row => [row.id, row])); // 合并基础数据与扩展数据 const mergedRawRows = basicRows.map(basicRow => ({ ...basicRow, ...extendedDataMap.get(basicRow.id) })); // 再执行前面的映射逻辑生成DataGrid行数组 const dataGridRows = mergedRawRows.map(rawRow => { const row: Record<string, any> = {}; requiredFields.forEach(field => { row[field] = rawRow[field] ?? null; }); return row; });
- 字段名映射兼容(可选)
若API返回的原始数据字段名与columns中的field不匹配,可在columns中添加自定义属性(如apiField)来做映射:
// 假设API返回的columns包含apiField属性,对应原始数据的字段名 const apiColumns: (GridColDef & { apiField?: string })[] = await fetch('/api/columns').then(res => res.json()); const dataGridRows = rawRows.map(rawRow => { const row: Record<string, any> = {}; apiColumns.forEach(col => { // 优先使用apiField匹配原始数据字段,无则用field const sourceField = col.apiField ?? col.field; row[col.field] = rawRow[sourceField] ?? null; }); // 确保行唯一标识存在 row.id = rawRow.id ?? rawRow[apiColumns.find(col => col.field === 'id')?.apiField] ?? null; return row; });
- DataGrid组件使用
最后将处理好的列和行数据传入组件:
<DataGrid columns={apiColumns} rows={dataGridRows} // 若未使用id作为唯一标识,需配置getRowId // getRowId={(row) => row.yourUniqueKey} />
关键注意事项
- 行唯一标识:DataGrid要求每行必须有唯一标识,默认是
id字段,若使用其他字段需通过getRowId属性指定。 - 空值处理:原始数据中不存在的字段建议设为
null或空字符串,避免组件渲染异常。 - 类型安全:TypeScript项目中可通过定义接口约束原始数据和行数据的类型,避免类型错误。
内容的提问来源于stack exchange,提问作者Okta
相关产品推荐
相关产品推荐

