React: Upload & Download files

Create and download a file from within the browser. File uploads too.

by Larry Kluger

HTML

<!-- HTML 5 !    -->
<div id="app"></div>

CSS

body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}

.hidden {
  display: none;
}

th {
  font-weight: bold;  
}

form {
  margin-top: 12px;
}

h2 {
  font-weight: bold;
  margin-bottom: 15px;
}

.mr {
  margin-right: 5px;
}

p,pre,.mt {
  margin-top: 15px;
}

pre.status {
    font-family: Helvetica;
}

input {
  margin-right: 5px;
}

React

class App extends React.Component {
  constructor(props) {
    super(props)
    
    const defaultFileType = "json"; 
    this.fileNames = {
    	json: "states.json",
      csv: "states.csv",
      text: "states.txt"
    }    
    this.state = {
      fileType: defaultFileType,
      fileDownloadUrl: null,
      status: "",
    	data: [
      	{ state: "Arizona",        electors: 11 },
      	{ state: "Florida",        electors: 29 },
      	{ state: "Iowa",           electors:  6 },
      	{ state: "Michigan",       electors: 16 },
      	{ state: "North Carolina", electors: 15 },
      	{ state: "Ohio",           electors: 18 },
      	{ state: "Pennsylvania",   electors: 20 },
      	{ state: "Wisconsin",      electors: 10 },
      ]
    }
  	this.changeFileType = this.changeFileType.bind(this);
  	this.download = this.download.bind(this);
  	this.upload = this.upload.bind(this);
  	this.openFile = this.openFile.bind(this);
  }
  
  changeFileType (event) {
    const value = event.target.value;
  	this.setState({fileType: value});
  }
  
  download (event) {
    event.preventDefault();
  	// Prepare the file
    let output;
    if (this.state.fileType === "json") {
    	output = JSON.stringify({states: this.state.data}, 
      	null, 4);
    } else if (this.state.fileType === "csv"){
      // Prepare data:
      let contents = [];
      contents.push (["State", "Electors"]);
      this.state.data.forEach(row => {
      	contents.push([row.state, row.electors])
      });
      output = this.makeCSV(contents);
    } else if (this.state.fileType === "text"){
      // Prepare data:
      output = '';
      this.state.data.forEach(row => {
      	output += `${row.state}: ${row.electors}\n`
      });
    }
    // Download it
    const blob = new Blob([output]);
    const fileDownloadUrl = URL.createObjectURL(blob);
    this.setState ({fileDownloadUrl: fileDownloadUrl}, 
      () => {
        this.dofileDownload.click(); 
        URL.revokeObjectURL(fileDownloadUrl);...