如何将React响应下载为文件
这是其中的代码 actions.js
export function exportRecordToExcel(record) {    return ({fetch}) => ({
        type: EXPORT_RECORD_TO_EXCEL,
        payload: {
            promise: fetch('/records/export', {
                credentials: 'same-origin',
                method: 'post',
                headers: {'Content-Type': 'application/json'},
                body: JSON.stringify(data)
            }).then(function(response) {
                return response;
            })
        }
    });
}
返回的响应是一个.xlsx文件。我希望用户能够将其保存为文件,但是什么也没有发生。我认为服务器返回的响应类型正确,因为在控制台中它说
Content-Disposition:attachment; filename="report.xlsx"我想念的是什么?我应该在减速器中做什么?
回答:
浏览器技术当前不支持直接从Ajax请求下载文件。解决方法是添加一个隐藏的表单并将其提交到幕后,以使浏览器触发“保存”对话框。
我正在运行标准的Flux实现,因此不确定确切的Redux(Reducer)代码应该是什么,但是我刚刚为文件下载创建的工作流是这样的…
- 我有一个叫做的React组件
FileDownload。该组件所做的全部工作就是呈现一个隐藏的表单,然后在内部componentDidMount立即提交表单并将其称为onDownloadCompleteprop。 - 我还有另一个React组件,我们称之为
Widget下载按钮/图标(实际上很多…一个用于表中的每个项目)。Widget具有相应的操作和存储文件。Widget进口FileDownload。 Widget有两种与下载相关的方法:handleDownload和handleDownloadComplete。Widget商店有一个名为的属性downloadPath。null默认设置为。如果将其值设置为null,则不会进行任何文件下载,并且该Widget组件不会呈现该FileDownload组件。- 单击中的按钮/图标
Widget将调用handleDownload触发downloadFile动作的方法。该downloadFile操作不会发出Ajax请求。它将DOWNLOAD_FILE事件分发给商店,并随事件一起发送downloadPath文件下载。商店保存downloadPath并发出更改事件。 - 因为现在有
downloadPath,Widget将呈现FileDownload传递必要的道具包括downloadPath以及所述handleDownloadComplete方法作为值onDownloadComplete。 - 当
FileDownload被渲染和表单被提交method="GET"(POST应太)和action={downloadPath},服务器的响应现在将触发浏览器的保存对话框目标下载文件(在IE 9/10测试,最新的Firefox和Chrome)。 - 在表单提交之后,立即调用
onDownloadComplete/handleDownloadComplete。这将触发另一个调度DOWNLOAD_FILE事件的动作。但是,这次downloadPath设置为null。商店将另存为downloadPath,null并发出更改事件。 - 由于不再存在
downloadPath,FileDownload因此不会渲染组件Widget,因此世界是一个快乐的地方。 
Widget.js-仅部分代码
import FileDownload from './FileDownload';export default class Widget extends Component {
    constructor(props) {
        super(props);
        this.state = widgetStore.getState().toJS();
    }
    handleDownload(data) {
        widgetActions.downloadFile(data);
    }
    handleDownloadComplete() {
        widgetActions.downloadFile();
    }
    render() {
        const downloadPath = this.state.downloadPath;
        return (
            // button/icon with click bound to this.handleDownload goes here
            {downloadPath &&
                <FileDownload
                    actionPath={downloadPath}
                    onDownloadComplete={this.handleDownloadComplete}
                />
            }
        );
    }
widgetActions.js-仅部分代码
export function downloadFile(data) {    let downloadPath = null;
    if (data) {
        downloadPath = `${apiResource}/${data.fileName}`;
    }
    appDispatcher.dispatch({
        actionType: actionTypes.DOWNLOAD_FILE,
        downloadPath
    });
}
widgetStore.js-仅部分代码
let store = Map({    downloadPath: null,
    isLoading: false,
    // other store properties
});
class WidgetStore extends Store {
    constructor() {
        super();
        this.dispatchToken = appDispatcher.register(action => {
            switch (action.actionType) {
                case actionTypes.DOWNLOAD_FILE:
                    store = store.merge({
                        downloadPath: action.downloadPath,
                        isLoading: !!action.downloadPath
                    });
                    this.emitChange();
                    break;
FileDownload.js-
完整,功能齐全的代码,可供复制和粘贴
-带Babel 6.x的React 0.14.7 [“ es2015”,“ react”,“ stage-0”]
-表单必须display: none是“隐藏的”形式“ className是为了
import React, {Component, PropTypes} from 'react';import ReactDOM from 'react-dom';
function getFormInputs() {
    const {queryParams} = this.props;
    if (queryParams === undefined) {
        return null;
    }
    return Object.keys(queryParams).map((name, index) => {
        return (
            <input
                key={index}
                name={name}
                type="hidden"
                value={queryParams[name]}
            />
        );
    });
}
export default class FileDownload extends Component {
    static propTypes = {
        actionPath: PropTypes.string.isRequired,
        method: PropTypes.string,
        onDownloadComplete: PropTypes.func.isRequired,
        queryParams: PropTypes.object
    };
    static defaultProps = {
        method: 'GET'
    };
    componentDidMount() {
        ReactDOM.findDOMNode(this).submit();
        this.props.onDownloadComplete();
    }
    render() {
        const {actionPath, method} = this.props;
        return (
            <form
                action={actionPath}
                className="hidden"
                method={method}
            >
                {getFormInputs.call(this)}
            </form>
        );
    }
}
以上是 如何将React响应下载为文件 的全部内容, 来源链接: utcz.com/qa/431491.html
