在React表格中的CSV导出按钮

54

寻找一种方法在npmjs包(https://www.npmjs.com/package/react-table)的react表格中添加“导出为CSV”按钮。

我需要添加一个自定义按钮,将表格数据导出到csv或xls格式的excel表格中吗?


你是如何获取表格中的数据(例如应用筛选器后)。我想要导出应用筛选器后的数据,而不是提供整个原始数据。 - raj
最终我通过在React表格实例中设置一个引用并通过this.reactTable.getResolvedState().sortedData检索当前数据,使其正常工作。 - raj
你可以使用一个简单的函数来触发下载 https://gist.github.com/xargr/97f160e5ab1bbc513bc7a1acd4ed88e4 - xargr
4个回答

57

看看这个npm库 - https://www.npmjs.com/package/react-csv

例如 -

import {CSVLink, CSVDownload} from 'react-csv';

const csvData =[
  ['firstname', 'lastname', 'email'] ,
  ['John', 'Doe' , 'john.doe@xyz.com'] ,
  ['Jane', 'Doe' , 'jane.doe@xyz.com']
];
<CSVLink data={csvData} >Download me</CSVLink>
// or
<CSVDownload data={csvData} target="_blank" />

7
дҪҝз”Ёreact-tableж–ҮжЎЈдёӯе…ідәҺthis.reactTable.getResolvedState()зҡ„е»әи®®жқҘиҺ·еҸ–dataеұһжҖ§гҖӮ - DrMeers
2
此包不支持异步调用。 - Vivek S

55

这是集成的样子:

import React from "react";
import "react-dropdown/style.css";
import "react-table/react-table.css";
import ReactTable from "react-table";
import { CSVLink } from "react-csv";

const columns = [
  {
    Header: "name",
    accessor: "name", // String-based value accessors!
  },
  {
    Header: "age",
    accessor: "age",
  },
];

class AllPostPage extends React.Component {
  constructor(props) {
    super(props);
    this.download = this.download.bind(this);
    this.state = {
      tableproperties: {
        allData: [
          { name: "ramesh", age: "12" },
          { name: "bill", age: "13" },
          { name: "arun", age: "9" },
          { name: "kathy", age: "21" },
        ],
      },
      dataToDownload: [],
    };
  }

  download(event) {
    const currentRecords = this.reactTable.getResolvedState().sortedData;
    var data_to_download = [];
    for (var index = 0; index < currentRecords.length; index++) {
      let record_to_download = {};
      for (var colIndex = 0; colIndex < columns.length; colIndex++) {
        record_to_download[columns[colIndex].Header] =
          currentRecords[index][columns[colIndex].accessor];
      }
      data_to_download.push(record_to_download);
    }
    this.setState({ dataToDownload: data_to_download }, () => {
      // click the CSVLink component to trigger the CSV download
      this.csvLink.link.click();
    });
  }

  render() {
    return (
      <div>
        <div>
          <button onClick={this.download}>Download</button>
        </div>
        <div>
          <CSVLink
            data={this.state.dataToDownload}
            filename="data.csv"
            className="hidden"
            ref={(r) => (this.csvLink = r)}
            target="_blank"
          />
        </div>
        <div>
          <ReactTable
            ref={(r) => (this.reactTable = r)}
            data={this.state.tableproperties.allData}
            columns={columns}
            filterable
            defaultFilterMethod={(filter, row) =>
              String(row[filter.id])
                .toLowerCase()
                .includes(filter.value.toLowerCase())
            }
          />
        </div>
      </div>
    );
  }
}

export default AllPostPage;

这也适用于过滤器。


3
感谢提供如何将链接变成按钮的示例。 - timdewolf
5
不需要使用 react-csv,它只会让事情变得更加复杂。相反,使用 export-to-csv - Finesse
感谢您如此详细地完善了示例。 - Andre DiCioccio
似乎不再起作用了: "错误 Arrow函数不应返回赋值 no-return-assign" 发生在 "ref={(r) => this.csvLink = r}" - user1853517
1
@Switch https://dev59.com/C1YM5IYBdhLWcg3wvSPN#48413941 - best wishes
显示剩余3条评论

12
我在React + Typescript中实现了它,代码如下(没有依赖项):
  /**
   * @desc get table data as json
   * @param data
   * @param columns
   */
  const getTableDataForExport = (data: any[], columns: any[]) => data?.map((record: any) => columns
.reduce((recordToDownload, column) => (
  { ...recordToDownload, [column.Header]: record[column.accessor] }
), {}));

/**
 * @desc make csv from given data
 * @param rows
 * @param filename
 */
const makeCsv = async (rows: any[], filename: string) => {
  const separator: string = ';';
  const keys: string[] = Object.keys(rows[0]);

const csvContent = `${keys.join(separator)}\n${
  rows.map((row) => keys.map((k) => {
    let cell = row[k] === null || row[k] === undefined ? '' : row[k];

    cell = cell instanceof Date
      ? cell.toLocaleString()
      : cell.toString().replace(/"/g, '""');

    if (cell.search(/("|,|\n)/g) >= 0) {
      cell = `"${cell}"`;
    }
    return cell;
  }).join(separator)).join('\n')}`;

const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
  if (navigator.msSaveBlob) { // In case of IE 10+
    navigator.msSaveBlob(blob, filename);
  } else {
    const link = document.createElement('a');
    if (link.download !== undefined) {
      // Browsers that support HTML5 download attribute
      const url = URL.createObjectURL(blob);
      link.setAttribute('href', url);
      link.setAttribute('download', filename);
      link.style.visibility = 'hidden';
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
    }
  }
};

这张表格:

<Table data={data} columns={columns} />

以及按钮:

  <button
    type="button"
    onClick={() => makeCsv(getTableDataForExport(data, columns), `${filename}.csv`)}
  >
    Download table data CSV
  </button>

2
不错。对于任何想知道列应该长什么样的人,它看起来像这样:const columns = [ { Header: "名字", accessor: "first_name", }, { Header: "姓氏", accessor: "last_name", }, ];accessor 是你的数据数组中的值键。 - emmaakachukwu

4

我想借用best wishes非常有价值的回答,提供一个简化的下载实现方式。

  export = e => {
    const currentRecords = this.ReactTable.getResolvedState().sortedData;
    this.setState({ dataToDownload: this.dataToDownload(currentRecords, columns) }, () =>
      this.csvLink.link.click()
    );
  }

  dataToDownload = (data, columns) =>
    data.map(record =>
      columns.reduce((recordToDownload, column) => {
        recordToDownload[column.Header] = record[column.accessor];
        return recordToDownload;
      }, {})
    );

我使用这个方法来在一个组件中允许多个表格的导出,通过添加额外的export函数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接