Javascript 将 ReactJS 对象下载为文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31214677/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 06:23:24  来源:igfitidea点击:

Download a ReactJS object as a file

javascriptjqueryajaxreactjsreact-jsx

提问by fryeguy

I am building an application with a ReactJS front end that connects to an Express API server. Calls to the API are made using Ajax.

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

In one of my views, a table loads with "Export" links on each row. The Export links lead to a React route that calls an API endpoint which provides a CSV file to download.

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

If I hit the API endpoint directly with a valid request (outside the React app), a file download is initiated in my browser. Perfect! However, following the Export link from the React page attempts to load the view where the call to the API occurs. The table disappears from the view and is replaced by the file contents (on purpose to prove I have the data) but no file is downloaded.

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

Can I force a download of the contents of the response object as a file? Could this take place in the ajax success callback? I made an attempt with javascript but I'm struggling with the React virtual DOM... I assume this must be pretty straight forward but I'm stumped.

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

EDIT: Comments by @Blex helped me solve this issue! The solution is added to the code snippet...

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

Here is the JSX that receives the data:

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

回答by fryeguy

Adding the following code based on comments by @blex got the file download working. To see it in context, take a look at the success callback in the question.

根据@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();

回答by Neo

I used a package jsonexportin my React app and now I am able to download the csv file on a link click. Here is what I did:

我在我的 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

.
.
.

Create a function that will provide data for CSV. It can also be in a callback from a network request. When this method is called, it will set value in filedownloadlinkstate.

创建一个为 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);
    });
}

In the render function use something like this:

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

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

The above link will be visible when filedownloadlinkhas some data to download.

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