Cmaxster
Cmaxster

Reputation: 1195

Accessing Upload Data in React From Multer Node Server

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

Answers (1)

devserkan
devserkan

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

Related Questions