将 ReactJS 对象下载为文件

Download a ReactJS object as a file

我正在构建一个带有连接到 Express API 服务器的 ReactJS 前端的应用程序。使用 Ajax.

调用 API

在我的一个观点中,table 每行加载 "Export" link。 Export links 导致 React 路由调用 API 端点,该端点提供 CSV 文件下载。

如果我使用有效请求(在 React 应用程序之外)直接点击 API 端点,则会在我的浏览器中启动文件下载。完美的!但是,在 React 页面的 Export link 之后,尝试加载调用 API 的视图。 table 从视图中消失并被文件内容取代(目的是证明我有数据)但没有文件被下载。

我可以强制将响应对象的内容下载为文件吗? 这会在 ajax 成功回调中发生吗? 我尝试使用 javascript 但我正在努力使用 React 虚拟 DOM... 我想这一定很简单,但我很困惑。

编辑:@Blex 的评论帮助我解决了这个问题!解决方案添加到代码片段中...

这里是接收数据的JSX:

module.exports = React.createClass({

    mixins: [Router.State],
    getInitialState: function() {
        return {
            auth: getAuthState(),
            export: [],
            passedParams: this.getParams()
        };
    },

    componentDidMount: function(){
        $.ajax({
            type: 'GET',
            url: ''+ API_URL +'/path/to/endpoint'+ this.state.passedParams.id +'/export',
            dataType: 'text',
            headers: {
                'Authorization': 'Basic ' + this.state.auth.base + ''
            },
            success: function (res) {
                // can I force a download of res here?
                console.log('Export Result Success -- ', res);
                if(this.isMounted()){
                    console.log('Export Download Data -- ', res);
                    this.setState({export: res[1]});
                    // adding the next three lines solved my problem
                    var data = new Blob([res], {type: 'text/csv'});
                    var csvURL = window.URL.createObjectURL(data);
                    //window.open(csvURL);
                    // then commenting out the window.open & replacing
                    // with this allowed a file name to be passed out
                    tempLink = document.createElement('a');
                    tempLink.href = csvURL;
                    tempLink.setAttribute('download', 'filename.csv');
                    tempLink.click();
                }
            }.bind(this),
            error: function (data) {
                console.log('Export Download Result Error -- ', data);
            }
        });
    },

    render: function(){
        console.log('exam assignment obj -- ', this.state.passedParams.name);
        var theFileContents = this.state.export;
            return(
            <div className="row test-table">
                <table className="table" >
                    <tr className="test-table-headers">
                    {theFileContents} // this loads the contents
                    // can I auto download theFileContents?
                    </tr>
                </table>
            </div>
            )
    }
});

根据@blex 的评论添加以下代码使文件下载正常进行。要在上下文中查看它,请查看问题中的成功回调。

var data = new Blob([res], {type: 'text/csv'});
var csvURL = window.URL.createObjectURL(data);
tempLink = document.createElement('a');
tempLink.href = csvURL;
tempLink.setAttribute('download', 'filename.csv');
tempLink.click();

我在我的 React 应用程序中使用了一个包 jsonexport,现在我可以通过单击 link 下载 csv 文件。 这是我所做的:

.
.
import React, {useState,useEffect} from 'react';// I am using React Hooks
import * as jsonexport from "jsonexport/dist";
.
.
.
const [filedownloadlink, setFiledownloadlink] = useState("");//To store the file download link

.
.
.

创建一个将为 CSV 提供数据的函数。它也可以在网络请求的回调中。当这个方法被调用时,它会在 filedownloadlink 状态设置值。

function handleSomeEvent(){
var contacts = [{
        name: 'Bob',
        lastname: 'Smith'
    },{
        name: 'James',
        lastname: 'David'
    },{
        name: 'Robert',
        lastname: 'Miller' 
    },{
        name: 'David',
        lastname: 'Martin'
    }];

    jsonexport(contacts,function(err, csv){
        if(err) return console.log(err);
        var myURL = window.URL || window.webkitURL //window.webkitURL works in Chrome and window.URL works in Firefox
        var csv = csv;  
        var blob = new Blob([csv], { type: 'text/csv' });  
        var csvUrl = myURL.createObjectURL(blob);
        setFiledownloadlink(csvUrl);
    });
}

在渲染函数中使用这样的东西:

{filedownloadlink &&<a download="UserExport.csv" href={filedownloadlink}>Download</a>}

filedownloadlink有一些数据要下载时,上面的link将可见。

添加以下代码以供将来参考。这包括对浏览器兼容性的一些额外检查和包含 IE10+ 的额外代码。

/* Take a blob and force browser to click a link and save it from a download path
     * log out timing
     *
     * @param {Blob}
     * @method saveFile
     */
    function saveFile(blob) {
        const uniqTime = new Date().getTime();
        const filename = `my_file_${uniqTime}`;

        if (navigator.msSaveBlob) { // IE 10+
            console.info('Starting call for ' + 'ie download');
            const csvFormatTimeStart = new Date().getTime();

            const ieFilename = `${filename}.csv`;
            navigator.msSaveBlob(blob, ieFilename);

            const csvFormatTimeEnd = new Date().getTime();
            const csvFormatTime = csvFormatTimeEnd - csvFormatTimeStart;
            console.log('ie download takes ' + csvFormatTime + ' ms to run');
        } else {
            console.info('Starting call for ' + 'regular download');
            const csvFormatTimeStart = new Date().getTime();
            let link = document.createElement("a");
            if (link.download !== undefined) { // feature detection
                // Browsers that support HTML5 download attribute
                var 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);
            }

            const csvFormatTimeEnd = new Date().getTime();
            const csvFormatTime = csvFormatTimeEnd - csvFormatTimeStart;
            console.log('regular download takes ' + csvFormatTime + ' ms to run');
        }

        clickEnd = new Date().getTime();
        console.log('The whole process took: ' + (clickEnd - clickStart) + ' ms');
    }

应归功于 this article