将 ReactJS 对象下载为文件

Posted

技术标签:

【中文标题】将 ReactJS 对象下载为文件【英文标题】:Download a ReactJS object as a file 【发布时间】:2015-09-21 18:14:21 【问题描述】:

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

在我的一个视图中,表格的每一行都加载了“导出”链接。导出链接指向一个调用 API 端点的 React 路由,该端点提供 CSV 文件以供下载。

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

我可以强制将响应对象的内容下载为文件吗? 这会发生在 ajax 成功回调中吗? 我尝试使用 javascript,但我在 React 虚拟 DOM 上苦苦挣扎…… 我想这一定很简单,但我很难过。

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

这是接收数据的 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>
            )
    
);

【问题讨论】:

你可以这样:jsfiddle.net/8f2ah406这里唯一的问题是文件名和扩展名需要在提示时手动设置。否则,只需window.open(/* URL of the Ajax request */); 效果很好!现在我只需要弄清楚如何自动设置文件名。 相关:***.com/questions/14964035/… 你去:jsfiddle.net/unmf5dp0 感谢@PeeyushKushwaha 提供链接。在常规的 javascript 中,我认为这很好用。但是,我在 React JS 环境中工作,将 javascript DOM 从用户那里抽象出来。虚拟 DOM 的概念对我来说仍然很陌生,并且使许多任务变得复杂。 【参考方案1】:

@blex 基于 cmets 添加以下代码使文件下载工作正常。要在上下文中查看它,请查看问题中的成功回调。

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();

【讨论】:

如果将 tempLink 附加到正文中,它也可以在 Firefox 中使用。不确定 Safari。 我不会在 Reactjs 中使用这种方法,因为它会重新生成整个 dom 树。 tempLink变量添加var 这个方法可以处理任何真实大小的文件吗?我的意思是,将对象创建为 URL?这真的能处理一个 4GB 的文件吗? 最初的帖子大约是六年前的事了,但如果我没记错的话,我试图完成的目的是提供一个选项,以下载以 CSV 格式显示在页面上的数据。我想如果我可以查看页面上的数据,我看不出大文件会失败的原因。但是,我怀疑我正在使用的任何数据是否超过几 MB,更不用说 GB。也许尝试一个测试用例。【参考方案2】:

我在我的 React 应用程序中使用了一个包 jsonexport,现在我可以通过单击链接下载 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 有一些数据要下载时,上面的链接将可见。

【讨论】:

【参考方案3】:

添加以下代码以供将来参考。这包括对浏览器兼容性的一些额外检查以及包括 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。

【讨论】:

以上是关于将 ReactJS 对象下载为文件的主要内容,如果未能解决你的问题,请参考以下文章

reactjs如何下载文件

从服务器 Laravel 和 reactjs 下载文件

ReactJS:单击按钮下载 CSV 文件

ReactJS:将 html 文件转换为 React 组件

reactjs-Axios 帖子返回空对象

在 ReactJS 应用程序中将字符串转换为 JSON 对象时出错