web-dev-qa-db-ja.com

ReactJSオブジェクトをファイルとしてダウンロードする

ExpressAPIサーバーに接続するReactJSフロントエンドを使用してアプリケーションを構築しています。 APIの呼び出しは、Ajaxを使用して行われます。

私の見解の1つでは、テーブルが読み込まれ、各行に「エクスポート」リンクがあります。エクスポートリンクは、ダウンロードするCSVファイルを提供するAPIエンドポイントを呼び出すReactルートにつながります。

(Reactアプリの外部で)有効なリクエストでAPIエンドポイントに直接アクセスすると、ブラウザーでファイルのダウンロードが開始されます。完璧!ただし、Reactページから[エクスポート]リンクをたどると、APIの呼び出しが発生するビューを読み込もうとします。テーブルがビューから消え、ファイルの内容に置き換えられます(データがあることを証明するため)が、ファイルはダウンロードされません。

応答オブジェクトの内容をファイルとして強制的にダウンロードできますか?これは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>
            )
    }
});
9
fryeguy

@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();
16
fryeguy

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にダウンロードするデータがある場合に表示されます。

0
Neo