Multiple file uploads with React.js and typescript

Asked

Viewed 834 times

-1

I’m using middleware multer to upload files, but on the front end (with React.js) when using the form-data to get the files selected by the user , but I can’t send to the back-end, I’ve already tested the upload route with Insomnia and it worked fine , the problem lies in integrating with the same React. Data such as name, email and password usually arrive by formdata only files arrive empty (Empty).

multer.

import multer from 'multer'
import path from 'path'


const storage = multer.diskStorage({
    destination: (req, file, callback) =>{
        callback(null, path.resolve(__dirname, 'uploads')  )
    },
    filename: (req, file, callback) =>{
        callback(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname))
    }
})

const uploads = multer({ storage: storage  })

export default uploads

Usercontroller.ts

import { Request, Response } from 'express'
//import knex from '../database/conn'

class UserController {
    async create(request: Request, response: Response){
        response.json({
            user_data: request.body,
            files: request.files
        })
    }
}

export default UserController

Routes.

import express, { Router, Request, Response } from 'express'
import uploads from './multer'

import UserController from './controllers/UserController'
import MidiaController from './controllers/MidiaController'

const user_controller = new UserController()

const routes = express.Router()

//rota para cadastrado de usuário
routes.post('/cad-user', uploads.single('file'), user_controller.create)


export default routes

App.tsx

import React, { useState, ChangeEvent, FormEvent } from 'react';

import axios from 'axios'
import FormData from 'form-data'
import { Request, Response } from 'express'

import './app.css'
import styled from 'styled-components'

const Input = styled.input`
  border: none;
  border-bottom: 1px solid #a6a6a6;
  font-size: 18px;

  margin: 5px 0px 10px 0px;
  outline: none;
  background-color: transparent;
  padding: 5px 10px;
`

const BtnSubmit = styled.input`
  border: none;
  border-radius: 3px;
  padding: 8px 16px;
  font-size: 15px;
  color: #f1f1f1;
  background-color: #2488C6;

  width: 50%;
  margin: 20px 0px 0px 0px;
  cursor: pointer;
  outline: none;
  transition-duration: 0.4s;

  &:hover{
    opacity: 0.85;
  };
`

const TitleForm = styled.h1`
  width: 100%;
  padding: 5px 0px 20px 0px;
  text-align: center;
`

function App() {
  const [file, setFile] = useState()

  const [getFormData, setFormData] = useState({
    nome: '',
    email: '',
    senha: ''
  })

  const handleInputChange = (event: ChangeEvent<HTMLInputElement>) =>{
    // console.log(event.target.name, event.target.value)
    const { name, value } = event.target


    setFormData({
      ...getFormData,
      [ name ] : value
    })
  }

  const handleInputFileChange = (e: any) =>{
      setFile(e.target.files[0])
  } 

  async function handleSubmit(event: FormEvent){
      event.preventDefault()
      console.log('Arquivo selecionado')
      console.log(file)
      const { nome, email, senha } = getFormData

      let formData = new FormData()

      formData.append('nome', nome)
      formData.append('email', email)
      formData.append('senha', senha)
      formData.append('file', file)

      axios({
        url: 'http://localhost:3030/cad-user',
        method: 'POST',
        headers: { 'Content-Type': 'multipart/form-data' },
        data: formData
      })
      .then(response =>{
        console.log(response.data)
      })
      .catch(error =>{
        console.error('Erro capturado: ' + error)
      })
  }

  return (
    <div className="App">
      <form onSubmit={handleSubmit}>
        <TitleForm>Envie seu relato</TitleForm>
        <Input
          type="text"
          name="nome"
          id="nome"
          placeholder="Digite seu nome..."
          onChange={handleInputChange}
          multiple
        />

        <Input
          type="text"
          name="email"
          id="email"
          placeholder="Digite seu email..."
          onChange={handleInputChange}
        />

        <Input
          type="password"
          name="senha"
          id="senha"
          placeholder="Digite sua senha..."
          onChange={handleInputChange}
        />

        <Input
          type="file"
          name="files"
          id="files"
          onChange={handleInputFileChange}
          multiple
        />

        <BtnSubmit type="submit" value="Enviar Memória"/>

      </form>
    </div>
  );
}

export default App;

Remarks
Here I am assigning only the first file selected by the user, because I could not think of any way to send all at once , the idea at first would be to store in the database a single string containing all the links (path) of the files separated by ','(comma) to then be able to break this string with Function split, plus the main problem is related to the upload itself.

  const handleInputFileChange = (e: any) =>{
      setFile(e.target.files[0])
  }

Form print

inserir a descrição da imagem aqui

As you can see the files do not appear for the back-end. I already appreciate any kind of help, I have searched on several websites about uploading files with React and typescript , but unfortunately I have not succeeded yet.

1 answer

0

Man, on your route you’re using upload.single() I believe that using this way, you will accept only one file, and not multiple. Otherwise I am mistaken you need to use upload.array('file').

Browser other questions tagged

You are not signed in. Login or sign up in order to post.