Reputation: 1195
So I figured out how to upload files using React and Node. It appears to be working, but I'm still very new to this stuff, and I can't quite understand how to access the file I just uploaded in React. I want to have it so that you use a form in React to upload a zip file, and then I want to have some scripts unzip the uploaded file and perform some actions on the contents. I have my files uploading properly, but I'm not sure how to pass the filename data into React after upload..
My server file:
const port = process.env.PORT || 5000;
const express = require('express');
const bodyParser = require('body-parser');
const multer = require('multer');
const uuidv4 = require('uuid/v4');
const path = require('path');
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, './src/uploads');
},
filename: (req, file, cb) => {
const newFilename = `${uuidv4()}${path.extname(file.originalname)}`;
cb(null, newFilename);
},
});
var fileFilter = function (req, file, cb) {
if (
file.mimetype !== 'application/zip'
) {
req.fileValidationError = 'goes wrong on the mimetype';
return cb(new Error('mimetype does not match application/zip. upload rejected'));
}
console.log('>> fileFilter good = ',file.mimetype)
cb(null, true);
}
const upload = multer({ storage: storage, fileFilter: fileFilter });
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.post('/', upload.single('selectedFile'), (req, res) => {
res.send();
});
app.listen(port, () => console.log(`Server listening on port ${port}`));
My React File:
import React, { Component } from 'react';
import axios from 'axios';
class UserForm extends Component {
constructor() {
super();
this.state = {
description: '',
selectedFile: '',
};
}
onChange = (e) => {
switch (e.target.name) {
case 'selectedFile':
this.setState({ selectedFile: e.target.files[0] });
break;
default:
this.setState({ [e.target.name]: e.target.value });
}
}
onSubmit = (e) => {
e.preventDefault();
const { description, selectedFile } = this.state;
let formData = new FormData();
formData.append('description', description);
formData.append('selectedFile', selectedFile);
console.log('form data ',formData)
axios.post('/', formData)
.then((result) => {
console.log('>> (onSubmit) file upload result = ',result);
// access results...
})
.catch(function (error) {
console.log('>> ERROR FILE UPLAOD ',error);
alert('File upload failed. Please ensure you are uploading a .zip file only')
})
}
render() {
const { description, selectedFile } = this.state;
return (
<form onSubmit={this.onSubmit}>
<input
type="text"
name="description"
value={description}
onChange={this.onChange}
/>
<input
type="file"
name="selectedFile"
onChange={this.onChange}
/>
<button type="submit">Submit</button>
</form>
);
}
}
export default UserForm;
Upvotes: 1
Views: 2934
Reputation: 17638
In your case you are uploading a single file. So you need to return it from your /
route like this
app.post('/', upload.single('selectedFile'), (req, res) => {
res.send( req.file );
});
When you use Multer and upload a file like this, then req.file
will be your uploaded file here, which is selectedFile
. So, you need to return it to use where ever you want.
This req.file
has some information like originalname, filename, path
and so on. You can use those information on your front-end. For example, you can grab path
(which is the full path of the uploaded file) then use it in an <img>
element.
Specifically for your situation, you can hold an imagePath
state:
this.state = {
description: '',
selectedFile: '',
imagePath: '',
};
Then update your state within your axois' .then
method:
axios.post('/', formData)
.then((result) => {
this.setState({imagePath: result.data.path})
})
....
and use it in your component:
{this.state.imagePath && <img src={this.state.imagePath} /> }
This is a very simple example, logic can be more complex when your app gets bigger.
Upvotes: 3