React导出Ant Design表格至Excel遇props.children.reduce错误求助
Ant Design可编辑表格导出Excel(修复reduce报错)
报错原因
Uncaught TypeError: props.children.reduce is not a function 报错源于导出工具处理列配置时遇到非预期结构:
- 部分列的
dataIndex与数据源(dataSource)字段不匹配(如'Abrir'列的abrir、'Deletar'列的operation) - 列配置中的
render、filters等属性被导出工具误判为需要遍历的子节点 - 自定义导出函数的
max函数未处理空数组边界情况
修复方案
方案一:调整antd-table-saveas-excel使用逻辑
- 过滤不需要导出的操作类列
- 清理列配置,仅保留导出所需的核心属性(
title、dataIndex、key) - 确保导出列的
dataIndex与数据源字段完全匹配
修改后的导出触发函数:
const handleClick = () => { // 过滤并清理导出列 const exportColumns = columns .filter(col => ['id', 'name', 'age', 'address'].includes(col.dataIndex)) .map(col => ({ title: col.title, dataIndex: col.dataIndex, key: col.key })); const excel = new Excel(); excel .addSheet("test") .addColumns(exportColumns) .addDataSource(dataSource, { str2Percent: true }) .saveAs("Excel.xlsx"); };
方案二:修复自定义导出函数(excel.js)
- 给
max函数添加空数组处理逻辑 - 在列遍历过程中过滤无效列(无
dataIndex或数据源中不存在的字段)
修改后的excel.js关键部分:
// 修复max函数,处理空数组边界 function max(arr) { if (!arr.length) return 0; return arr.reduce((accu, curr) => curr > accu ? curr : accu); } // 修改列遍历逻辑,过滤无效列 function columnLine(column) { column.map(ele => { // 跳过无有效dataIndex的列 if (!ele.dataIndex || !dataSource[0]?.hasOwnProperty(ele.dataIndex)) { return; } if (ele.children === undefined || ele.children.length === 0) { columnLineArr.push(ele); } else { columnLine(ele.children); } }); }
在TableExcel.js中调用自定义函数:
import exportExcel from './excel.js'; const handleClick = () => { exportExcel(columns, dataSource, 'Excel'); };
完整可运行代码(方案一)
TableExcel.js
import { Table, Drawer, Tooltip, Popconfirm, Button } from "antd"; import { RiFileExcel2Line } from 'react-icons/ri'; import { DeleteOutlined, FolderOpenOutlined } from '@ant-design/icons'; import DrawerDB from "../../Drawer/DrawerDB"; import React, { useState } from 'react'; import { Excel } from "antd-table-saveas-excel"; export default function TableExcel() { const [open, setOpen] = useState(false); const showDrawer = () => setOpen(true); const onClose = () => setOpen(false); const [dataSource, setDataSource] = useState([ { key: "1", id: 156, name: "Emily", age: 32, address: "10 Downing Street" }, { key: "2", id: 336, name: "Joana", age: 42, address: "10 Downing Street" }, { key: "3", id: 2398, name: "Maria", age: 42, address: "10 Downing Street" } ]); const handleDelete = (id) => { setDataSource(dataSource.filter(item => item.id !== id)); }; const columns = [ { key: '4', title: 'Abrir', dataIndex: 'abrir', width: 80, render: () => ( <button onClick={showDrawer}> <FolderOpenOutlined /> </button> ) }, { key: '5', title: 'ID', dataIndex: 'id', ellipsis: true, width: 80 }, { key: '6', title: 'name', dataIndex: 'name', ellipsis: true, width: 150 }, { key: '7', title: 'age', dataIndex: 'age', ellipsis: true, width: 150 }, { key: '8', title: 'Address', dataIndex: 'address', ellipsis: true, width: 100, render: (address) => ( <Tooltip placement="topLeft" title={address}>{address}</Tooltip> ) }, { key: '9', title: 'Deletar', dataIndex: 'operation', width: 150, render: (_, record) => ( <Popconfirm title="Tem certeza que deseja deletar?" cancelText='Cancelar' onConfirm={() => handleDelete(record.id)}> <button><DeleteOutlined style={{ color: 'red', marginLeft: 15 }} /></button> </Popconfirm> ) } ]; const handleClick = () => { const exportColumns = columns .filter(col => ['id', 'name', 'age', 'address'].includes(col.dataIndex)) .map(col => ({ title: col.title, dataIndex: col.dataIndex, key: col.key })); const excel = new Excel(); excel.addSheet("test") .addColumns(exportColumns) .addDataSource(dataSource, { str2Percent: true }) .saveAs("Excel.xlsx"); }; return ( <> <div className="export-excel"> <Button className='btn' onClick={handleClick}> <RiFileExcel2Line /> </Button> </div> <Table columns={columns} dataSource={dataSource} style={{ padding: 35 }} /> <Drawer width={1100} title="Informações completas" placement="right" onClose={onClose} open={open}> <DrawerDB /> </Drawer> </> ); }
内容的提问来源于stack exchange,提问作者Joyce
相关产品推荐
相关产品推荐

