2016-02-04 5 views
26

यहाँ के रूप में प्रतिक्रिया में डाउनलोड करने के लिए में 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" 

मुझे क्या याद आ रही है? रेड्यूसर में मुझे क्या करना चाहिए?

उत्तर

34

ब्राउज़र तकनीक वर्तमान में सीधे अजाक्स अनुरोध से फ़ाइल डाउनलोड करने का समर्थन नहीं करती है। चारों ओर का काम एक छिपी हुई फॉर्म को जोड़ने और ब्राउज़र को सहेजें संवाद को ट्रिगर करने के लिए दृश्यों के पीछे सबमिट करना है।

मैं एक मानक फ्लक्स कार्यान्वयन चल रहा हूँ तो मुझे यकीन है कि क्या सही Redux (प्रसारण) कोड होना चाहिए नहीं कर रहा हूँ, लेकिन कार्यप्रवाह मैं सिर्फ एक फ़ाइल डाउनलोड के लिए बनाए गए इस प्रकार है ...

  1. मेरे पास FileDownload नामक एक प्रतिक्रिया घटक है। यह सब घटक एक छिपी हुई प्रपत्र प्रस्तुत करता है और फिर, componentDidMount के अंदर, तुरंत फॉर्म सबमिट करें और इसे onDownloadComplete प्रोप पर कॉल करें।
  2. मेरे पास एक और प्रतिक्रिया घटक है, हम इसे डाउनलोड बटन/आइकन (वास्तव में ... तालिका में प्रत्येक आइटम के लिए एक) के साथ Widget पर कॉल करेंगे। Widget में संबंधित कार्रवाई और स्टोर फ़ाइलें हैं। Widget आयात FileDownload
  3. Widget डाउनलोड से संबंधित दो विधियां हैं: handleDownload और handleDownloadComplete
  4. Widget स्टोर में downloadPath नामक एक संपत्ति है। यह डिफ़ॉल्ट रूप से null पर सेट है। जब यह मान null पर सेट किया गया है, तो कोई फ़ाइल डाउनलोड प्रगति पर नहीं है और Widget घटक FileDownload घटक प्रस्तुत नहीं करता है।
  5. Widget में बटन/आइकन पर क्लिक करने से handleDownload विधि कॉल होती है जो downloadFile क्रिया को ट्रिगर करती है। downloadFile कार्रवाई एक अजाक्स अनुरोध नहीं करता है। यह DOWNLOAD_FILE ईवेंट को फ़ाइल डाउनलोड करने के लिए downloadPath के साथ भेजकर स्टोर में भेजता है। स्टोर downloadPath बचाता है और एक परिवर्तन घटना उत्सर्जित करता है।
  6. के बाद से वहाँ अब एक downloadPath है, WidgetdownloadPath के साथ-साथ onDownloadComplete के लिए मूल्य के रूप में handleDownloadComplete विधि सहित आवश्यक रंगमंच की सामग्री में गुजर FileDownload प्रस्तुत करना होगा।
  7. जब FileDownload प्रस्तुत किया जाता है और फॉर्म method="GET" (POST भी काम करना चाहिए) और action={downloadPath} के साथ सबमिट किया गया है, तो सर्वर प्रतिक्रिया अब लक्ष्य डाउनलोड फ़ाइल के लिए ब्राउज़र के सहेजें संवाद को ट्रिगर करेगी (आईई 9/10, नवीनतम फ़ायरफ़ॉक्स और क्रोम में परीक्षण किया गया है))।
  8. फॉर्म सबमिट करने के तुरंत बाद, onDownloadComplete/handleDownloadComplete कहा जाता है। यह एक और क्रिया को ट्रिगर करता है जो DOWNLOAD_FILE ईवेंट भेजता है। हालांकि, इस बार downloadPathnull पर सेट है। स्टोर downloadPath को null के रूप में सहेजता है और एक परिवर्तन ईवेंट उत्सर्जित करता है।
  9. चूंकि अब downloadPathFileDownload घटक 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। जेएस
- कॉम प्रतिलिपि, पूरी तरह से कार्यात्मक कोड कॉपी और पेस्ट के लिए तैयार
- बैबेल 6.x ["es2015", "प्रतिक्रिया", "चरण -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> 
     ); 
    } 
} 
+0

@nate सीए एन हेडर जानकारी इस फॉर्म सबमिशन के साथ पैक किया जा सकता है? – charlie

+1

@charlie यह एक मानक HTML फॉर्म सबमिट है। आप सामग्री-प्रकार HTTP शीर्षलेख के तीन अलग-अलग मान निर्दिष्ट करने के लिए 'enctype' विशेषता का उपयोग कर सकते हैं, लेकिन यह सब कुछ है। [प्रेषण फ़ॉर्म डेटा] (https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Forms/Sending_and_retrieving_form_data) MDN पर पृष्ठ उपयोगी हो सकता है। शीर्षक वाले अनुभाग पर एक नज़र डालें * एक विशेष मामला: फाइलें भेजना *। हमारे पास एक उपयोग केस है जहां हम पहले डाउनलोड फ़ाइल उत्पन्न करने के लिए एक अजाक्स अनुरोध भेजते हैं, फिर हम डाउनलोड करते हैं। यदि आप उस विकल्प का उपयोग कर सकते हैं, तो आपके अजाक्स अनुरोध में हेडर पर अधिक नियंत्रण होगा। – Nate

+0

यह उदाहरण बहुत उपयोगी है, लेकिन यह अभी भी मुझे स्पष्ट नहीं है कि यह कार्यान्वयन इस बारे में जानता है कि फ़ाइल डाउनलोड की गई है या नहीं। मैं देखता हूं कि सबमिट करने के बाद "ऑनडाउनलोड" को सिंक्रनाइज़ कहा जाता है, क्या आप केवल यह धारणा बना रहे हैं कि कोई त्रुटि नहीं है और सर्वर को अनुरोध प्राप्त होता है? – Himmel

20

आप फ़ाइलों http://danml.com/download.htmlhttps://github.com/eligrey/FileSaver.js/#filesaverjs

उदाहरण डाउनलोड करने के लिए इन दो libs का उपयोग कर सकते

// for FileSaver 
import FileSaver from 'file-saver'; 
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.blob(); 
      }).then(function(blob) { 
      FileSaver.saveAs(blob, 'nameFile.zip'); 
      }) 
     } 
     }); 

// for download 
let download = require('./download.min'); 
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.blob(); 
      }).then(function(blob) { 
      download (blob); 
      }) 
     } 
     }); 
संबंधित मुद्दे