send an image file from react to node.js - node.js

I am currently working upload a profile picture and save the picture at aws s3 bucket.
When I send an image file through Postman, there were no error just works fine. I was able to upload a file to multer and aws s3.
However, when I tried to upload a picture through react front-end, It doesn't show any file. req.file is undefined.
I tried to figure this problem for weeks but still have no clue. I tried data.append profilepic[0] but it still didn't work.
React Code
clickSubmit = event => {
event.preventDefault()
const {profilepic, fname, lname, password, passwordconfirm} = this.state
const data = new FormData();
console.log(profilepic[0]);
// data.append('profilepic', profilepic[0], profilepic[0].name);
const user ={
fname,
lname,
password,
passwordconfirm,
profilepic
};
console.log(user);
this.signup(user).then(data => {
console.log(data)
if(data.error) {
this.setState({error: data.error});
}
else{
this.setState({
fname:"",
lname: "",
password: "",
error: "",
open: true,
passwordconfirm: "",
// profilepic: [],
});
}
});
};
onDrop(picture) {
this.setState({
profilepic: picture,
});
console.log(this.state.profilepic);
}
signup = user => {
return fetch("http://localhost:3003/auth/mtregister",{
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "http://localhost:3003"
},
body: JSON.stringify(user)
})
.then(response => {
return response.json();
})
.catch(err => console.log(err));
}
inspect console shows file information
console from front-end
mtregister node.js
const db = require('../../dbconfig.js');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const {promisify} = require('util');
const nodemailer = require('nodemailer');
const multer = require('multer');
const fs = require('fs');
const aws = require('aws-sdk');
aws.config.update({
accessKeyId: process.env.AWS_KEY,
secretAccessKey: process.env.AWS_SECRET_KEY,
region: 'us-east-1',
});
//Creating a new instance of S3:
const s3= new aws.S3();
// Set up Multer Storage
const storage = multer.diskStorage({
destination: "../../public/images",
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
})
const upload = multer({ storage: storage });
/*mentor register*/
exports.mtregister = [upload.single('profilepic'), async(req,res)=>
{
console.log(req.body);
console.log(req.file);
....
}
the output of console.log(req.body);console.log(req.file); is empty [ {} ] and undefined.
console.log results

I recommend use Axios to make http request from React. The Docummentation is good.
Example from: https://www.nicesnippets.com/blog/react-js-file-upload-example-with-axios
import React from 'react'
import axios from 'axios';
class FileUpload extends React.Component{
constructor(){
super();
this.state = {
selectedFile:'',
}
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(event) {
this.setState({
selectedFile: event.target.files[0],
})
}
submit(){
const data = new FormData()
data.append('file', this.state.selectedFile)
console.warn(this.state.selectedFile);
let url = "http://localhost:8000/upload.php";
axios.post(url, data, { // receive two parameter endpoint url ,form data
})
.then(res => { // then print response status
console.warn(res);
})
}
render(){
return(
<div>
<div className="row">
<div className="col-md-6 offset-md-3">
<br /><br />
<h3 className="text-white">React File Upload - Nicesnippets.com</h3>
<br />
<div className="form-row">
<div className="form-group col-md-6">
<label className="text-white">Select File :</label>
<input type="file" className="form-control" name="upload_file" onChange={this.handleInputChange} />
</div>
</div>
<div className="form-row">
<div className="col-md-6">
<button type="submit" className="btn btn-dark" onClick={()=>this.submit()}>Save</button>
</div>
</div>
</div>
</div>
</div>
)
}
}
export default FileUpload;

Related

MulterError: Unexpected field error while uploading image from React js

All the answers related this error is directing towards checking the name upload.single("image") and the name attribute of the file input in client side, which is in my case same as "image" as multer. But still it is giving the error.
Following is the node js code:
const Imagestorage = multer.memoryStorage()
const upload = multer({ storage: Imagestorage })
app.post("/newpost", upload.single("image"), async(req, res) => {
console.log(req.body);
console.log(req.file);
let data={}
// convert base64 image data to string using datauri/parser, upload to cloudinary and send response
const extName = path.extname(req.file.originalname).toString();
const file64 = parser.format(extName, req.file.buffer);
const filename=file64.content
cloudinary.uploader.upload(filename, async(error, result) => {
if (error) {
res.status(500).send("error in uploading file to cloudinary"+error);
} else {
// result.secure_url is the URL of the uploaded file on Cloudinary
console.log(result.secure_url);
let Imageurl=await result.secure_url
data={
name: req.body.name,
location:req.body.location,
likes:req.body.likes,
description:req.body.description,
image:Imageurl
}
console.log(data)
let postedData=await postsModel.create(data)
res.json({
status:"ok",
postedData
})
}
});
});
//error field in case something happens with multer
// app.use((error, req, res, next) => {
// console.log('This is the rejected field ->', error.field);
// });
app.get("*", (req, res) => {
res.status(404).send("PAGE IS NOT FOUND");
})
Frontend code-
import axios from "axios";
import { useNavigate } from "react-router-dom";
const Form = () => {
const navigate = useNavigate();
function handleSubmit(event) {
event.preventDefault();
const formData = new FormData(event.target);
// Append the file input to the form data
const imageFile = formData.get("image");
formData.append("image", imageFile);
// Use Axios to send a POST request to your server with the form data
axios
.post("https://instabackend-gcwk.onrender.com/newpost", formData, {
//.post("http://127.0.0.1:5000/newpost", formData, {
headers: {
"Content-Type": "multipart/form-data"
}
})
.then((response) => {
console.log(response);
})
.catch((error) => {
console.error(error);
})
.finally(navigate("/insta"));
}
return (
<div>
<form onSubmit={handleSubmit}>
<label htmlFor="image">Image:</label>
<input type="file" id="image" name="image" accept="image/*" />
<button type="submit">Submit</button>
</form>
<button onClick={() => navigate(-1)}>Go Back Home</button>
</div>
);
};
export default Form;
When i tried -
app.use((error, req, res, next) => {
console.log('This is the rejected field ->', error.field);
});
it's giving error field as "This is the rejected field -> image "
Note: There is no issue in fetching the data
Replacing append with set of FormData() is making the code work. Javascript.info explains the working of formData() here
import axios from "axios";
const App = () => {
function handleSubmit(event) {
event.preventDefault();
const formData = new FormData(event.target);
//get image
const imageFile = formData.get("image");
//set image
formData.set("image", imageFile);
axios
.post("https://instabackend-gcwk.onrender.com/newpost", formData, {
headers: {
"Content-Type": "multipart/form-data"
}
})
.then((response) => {
console.log(response);
})
.catch((error) => {
console.error(error);
});
}
return (
<div>
<form onSubmit={handleSubmit}>
<label htmlFor="image">Image:</label>
<input type="file" id="image" name="image" accept="image/*" />
<button type="submit">Submit</button>
</form>
</div>
);
};
export default App;

req.file is showing undefined in console

I am trying to upload a video on youtube from my web app but I am getting an error in sending a file to my backend it is showing the req.file as undefined in req.body it is showing videoFile: "Undefined" and all other values I can see but I am not able to get the file from my react app to backend .
Input.jsx
import axios from "axios";
import React, { useState } from "react";
// import Axios from "axios";
function Input() {
const [form, setForm] = useState({
title: "",
description: "",
file: null,
});
function handleChange(event) {
const InputValue =
event.target.name === "file" ? event.target.file : event.target.value;
setForm({
...form,
[event.target.name]: InputValue,
});
}
function handleSubmit(event) {
event.preventDefault();
console.log({ form });
const headers = {
"content-type": "multipart/form-data",
};
const videoData = new FormData();
videoData.append("videoFile", form.file);
videoData.append("title", form.title);
videoData.append("description", form.description);
axios
.post("http://localhost:3001/upload", videoData, { headers })
.then((res) => {
console.log(res.data);
})
.catch((err) => console.log(err));
}
return (
<div className="form">
<h1>
<i className="fab fa-youtube"></i> Upload video
</h1>
<form onSubmit={handleSubmit} method="POST" enctype="multipart/form-data">
<div>
<input
className="title"
type="text"
placeholder="Title"
name="title"
autoComplete="off"
onChange={handleChange}
/>
</div>
<div>
<textarea
typeof="text"
placeholder="description"
name="description"
autoComplete="off"
onChange={handleChange}
/>
</div>
<div>
<input
type="file"
accept="video/mp4,video/x-m4v,video/*"
placeholder="Add"
name="file"
onChange={handleChange}
/>
</div>
<button className="btn btn-light" type="submit">
Upload Video
</button>
</form>
</div>
);
}
export default Input;
it is node.js part
App.js (backend)
const express = require("express");
const multer = require("multer");
const youtube = require("youtube-api");
const open = require("open");
const cors = require("cors");
const fs = require("fs");
const credentials = require("./client_secret_1013548512515-lti2tpl88m8qqkum1hh095cnevtdi3lu.apps.googleusercontent.com.json");
const app = express();
const bodyParser = require("body-parser");
app.use(express.json());
app.use(cors());
app.use(bodyParser.urlencoded({ extended: true }));
const storage = multer.diskStorage({
destination: "./",
filename: (req, file, cb) => {
const newFileName = `${Date.now()}-${file.originalname}`;
cb(null, newFileName);
},
});
const uploadVideoFile = multer({
storage: storage,
}).single("videoFile");
app.post("/upload", uploadVideoFile, (req, res) => {
console.log(req.body);
console.log(req.file); //it is showing undefined
if (req.file) { //getting error in this part
const filename = req.file.filename;
const { title, description } = req.body;
open(
oAuth.generateAuthUrl({
access_type: "offline",
scope: "https://www.googleapis.com/auth/youtube.upload",
state: JSON.stringify({
filename,
title,
description,
}),
})
);
}
});
app.get("/oauth2callback", (req, res) => {
res.redirect("http://localhost:3000/success");
const { filename, title, description } = JSON.parse(req.query.state);
oAuth.getToken(req.query.code, (err, tokens) => {
if (err) {
console.log(err);
return;
}
oAuth.setCredentials(tokens);
youtube.videos.insert(
{
resource: {
snippet: { title, description },
status: { privacyStatus: "private" },
},
part: "snippet,status",
media: {
body: fs.createReadStream(filename),
},
},
(err, data) => {
console.log("Done");
process.exit();
}
);
});
});
const oAuth = youtube.authenticate({
type: "oauth",
client_id: credentials.web.client_id,
client_secret: credentials.web.client_secret,
redirect_url: credentials.web.redirect_uris[0],
});
PORT = 3001;
app.listen(PORT, () => {
console.log("app is listening on port 3001");
});
Please make the following changes in the Input.jsx file.
// 1. Inside the handleChange() function
const InputValue = event.target.name === "file" ? event.target.files : event.target.value;
// 2. Inside the handleSubmit() function
videoData.append("videoFile", form.file[0], form.file[0].name);
This should output the file object inside req.file.

Upload image with Multer and Formik to Mongodb (MERN)

I created app using MERN.
Now I'm trying to upload image with Multer and Formik, but req.file returns undefined, and I can't understand why.
I'm new in this, but I guess this may cause from JSON.stringify (http.hook) or content-type: application/json. I also tried do this with FormData, but that's not working. Any ideas?
UPDATE: With Postman works good. I think problem is in ui part, input doesn,t pass the file.
app.js
const {Router} = require('express');
const multer = require('multer');
const auth = require('../middleware/auth.middleware');
const Users= require('../models/Users');
const router = Router();
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './client/public/uploads/');
},
filename: function (req, file, cb) {
cb(null, file.originalname);
},
});
const upload = multer({
storage: storage,
limits: { fileSize: 10 * 1024 * 1024 }
});
router.post('/create', upload.single('image'), auth, async (req, res) => {
console.log(req.file);
try {
const code = req.body.code;
const existing = await Users.findOne({code: code});
if(existing) {
return res.json({user: existing})
}
const user = new Users(req.body);
await user .save();
res.status(201).json(user);
} catch (e) {
console.log(e);
res.status(500).json({ message: 'Error: try again.' })
}
});
http.hook.js
import {useState, useCallback} from 'react';
export const useHttp = () => {
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const request = useCallback(async (url, method = 'GET', body = null, headers = {}) => {
setLoading(true);
try {
if(body) {
body = JSON.stringify(body);
headers['Content-Type'] = 'application/json';
}
const response = await fetch(url, {method, body, headers});
const data = await response.json();
if(!response.ok) {
throw new Error(data.message || 'Something goes wrong')
}
setTimeout(() => {
setLoading(false);
}, 800);
return data
} catch (e) {
setLoading(false);
setError(e.message);
throw e;
}
}, []);
const clearError = useCallback(() => {setError(null)}, []);
return {loading, request, error, clearError}};
CreateUser.js
import React, {useCallback, useContext, useEffect, useState} from 'react';
import {useHttp} from "../hooks/http.hook";
import Button from "../components/Button/Button";
import {AuthContext} from "../context/auth.context";
import {Formik} from "formik";
export const CreateUser = () => {
const {token} = useContext(AuthContext);
const {loading, request} = useHttp();
const createUser = useCallback(async (body) => {
try {
const fetched = await request(`/api/user/create`, 'POST', body, {
Authorization: `Bearer ${token}`
});
} catch (e) {console.log(e)}
}, []);
const handleCreate = (values, {resetForm}) => {
console.log(values);
createUser(values);
// resetForm({});
};
return (
<div className="wrapper">
<div className="row">
<div className="column small-12 text-center color-white mb_45">
<div className="custom-headline text text-48 font-bold">
<h1>
Crate user
</h1>
</div>
</div>
</div>
<Formik
enableReinitialize
initialValues={{
name: '',
code: '',,
image: null
}}
onSubmit={handleCreate}
>
{({
values,
errors,
touched,
handleBlur,
handleChange,
handleSubmit,
isSubmitting,
setFieldValue,
resetForm
}) => (
<form onSubmit={handleSubmit} className="row align-center">
<div className="column small-12 large-7">
<div className="form-item flex-container align-middle mb_20">
<label className="text text-14 font-semibold font-uppercase text-right small-4">
Photos
</label>
<input id="image" type="file" name="image" className="file_input"
onChange={(event) => {
setFieldValue("image", event.currentTarget.files[0]);
}} />
</div>
</div>
<div className="column small-12 large-7">
<div className="form-item flex-container align-middle mb_20">
<label className="text text-14 font-semibold font-uppercase text-right small-4">
Name
</label>
<input
className="text text-17 "
type="text"
name="name"
onChange={handleChange}
onBlur={handleBlur}
value={values.name}
/>
</div>
</div>
<div className="column small-12 large-7">
<div className="form-item flex-container align-middle mb_20">
<label className="text text-14 font-semibold font-uppercase text-right small-4">
Code
</label>
<input
className="text text-17"
type="text"
name="code"
onChange={handleChange}
onBlur={handleBlur}
value={values.code}
/>
</div>
</div>
<div className="column small-12 mt_20">
<div className="btn_group flex-container flex-wrap align-middle align-center">
<Button className="btn-lg radius-8" theme="blue"
text={Submit} type="submit"
/>
</div>
</div>
</form>
)}
</Formik>
</div>
)
};
Wrap out your image file with formData with the multer key "image"
upload.single('image')
on Front-End
const handleCreate = async (values) => {
try {
const body = new FormData();
body.append( "image", values.image);
...
} catch (err) {}
};
And make sure about your destination path use "dirname"
`${__dirname}/../client/public/uploads/`
Change this according to your directory path
OK! I don't know WHY this was cause, but I found solution - I use axios instead of fetch, and of course FormData for uploading images or files, and it works!
Hope this may be helpful for someone else. Thanks for all answers.
const handleCreate = (values, {resetForm}) => {
const formData = new FormData();
formData.append('name', values.name);
formData.append('code', values.code);
formData.append('image', values.image);
axios.post('/api/user/create', formData)
.then(console.log)
catch(console.error);
resetForm({});
};
I have 2-3 suggestion,
in your app.js file
router.post('/create', upload.single('image'), auth, async (req, res) => {
console.log(req.file);
you should use auth middelware before using upload.single.
and you should send headers with POST request with {content type: multipart/form-data}

Trying to send formData with another parameter via axios

I have a form that uploads single files via a FormData object. In addition to the file attribute, I want to also assign this file to a Group.
I can't figure out how to add the group object id to the request.
Here is my upload component:
<template>
<div>
<div class="ui attached segment rounded mb-3">
<form #submit.prevent="sendFile" enctype="multipart/form-data" class="ui form">
<div v-if="message" class="`message ${error ? 'text-danger' : 'text-success'}`">
<div class="message-body"> {{ message }}</div>
</div>
<div class="field">
<label for="file" class="label">Upload File</label>
<input
type="file"
ref="file"
#change="selectFile"
class="file-input"
/>
<!-- <span class="file-cta">
<span class="file-icon">
<i class="fas fa-upload"></i>
</span>
<span class="file-label">
Choose a file...
</span>
</span> -->
<span v-if="file" class="file-name">{{file.name}}</span>
<div class="field">
<button class="btn btn-info">Send</button>
</div>
</div>
</form>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: "SimpleUpload",
data() {
return {
file: "",
message: '',
error: false
}
},
computed: {
currentGroup() {
return this.$store.getters.currentGroup;
}
},
methods: {
selectFile() {
const file = this.$refs.file.files[0];
const allowedTypes = ["image/jpeg", "image/png", "image/gif"];
const MAX_SIZE = 200000;
const tooLarge = file.size > MAX_SIZE;
if (allowedTypes.includes(file.type) && !tooLarge) {
this.file = file;
this.error = false;
this.message = '';
} else {
this.error = true;
this.message = tooLarge ? `Too large. Max size is ${MAX_SIZE/1000}kb` : "Only images are allowed"
}
},
async sendFile() {
const formData = new FormData();
formData.append('file', this.file);
formData.append('group', this.currentGroup);
console.log('file is: ', this.file)
console.log('this is form data after file is added: ', formData)
try {
await axios.post('/uploads', {
formData,
group_id: this.currentGroup.id
});
console.log('this is the formData being sent: ', formData)
this.message = 'File has been uploaded';
this.file = '';
this.error = false;
} catch(err) {
this.message = err.response.data.error;
this.error = true
}
}
}
}
</script>
Here is my route in :
const Group = require('../models/Group');
const Upload = require('../models/Upload');
const router = express.Router();
const upload = require('../services/file-uploads');
const singleUpload = upload.single('file'); // has to match front end
router.post('/', auth.required, async function(req, res) {
console.log ('upload route is hit')
let results = await singleUpload(req, res, async function (err) {
if (err) {
return res.status(422).send({ errors: [{title: 'File upload error, detail: err.message'}] });
} else {
console.log('this is the upload reqest fobject: ', req);
console.log("trying to save data to postgres");
// console.log('this is the originalname of the reqest file object: ', req.file);
console.log('this is the upload reqest body: ', req.body.group_id);
await Upload.query()
.insert({
name: req.body.file.originalname,
users_id: req.user.id,
filetype: req.body.file.mimetype,
filesize: req.body.file.size,
file_url: req.body.file.location,
groups_id: req.body.group_id
})
res.json({
success: true,
message: 'ok'
});
res.json(results)
}
})
});
module.exports = router;
and the upload config in services/file-uploads:
const aws = require('aws-sdk');
const multer = require('multer');
const multerS3 = require('multer-s3');
aws.config.update({
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
region: 'us-east-1'
})
const s3 = new aws.S3();
const fileFilter = (req, file, cb) => {
if (file.mimetype === 'image/jpeg' || file.mimetype === 'image/png') {
cb(null, true)
} else {
cb(new Error('Invalid Mime Type, only JPEG and PNG'), false);
}
}
const upload = multer({
storage: multerS3({
s3: s3,
bucket: process.env.AWS_BUCKET,
acl: 'public-read',
metadata: function (req, file, cb) {
cb(null, {fieldName: 'TESTING_META_DATA!'});
},
key: function (req, file, cb) {
cb(null, Date.now().toString())
}
})
})
module.exports = upload;
In the request, I see body: { formData: {}, group_id: 1 },
and I can retrieve the group_id with req.body.id, but the formData object is empty
Prepare the FormData like this:
const formData = new FormData();
formData.append('file', this.file); // Append a file
formData.append('group_id', this.currentGroup.id); // Append a field
And then send it like this:
await axios({
method: 'post',
url: '/uploads',
data: formData,
headers: {
'Content-Type': 'multipart/form-data'
}
});

How to send a file/image from React to node.js server

I'm trying to send a file/image from React to node.js server with multer. The problem is I can send an image only through Postman but when I'm trying the same in React I'm getting: TypeError: Cannot read property 'path' of undefined. I don't understand whether I should send a file/image in binary or use another format. I've already tried to use reader.readAsDataURL() and reader.readAsBinaryString() but it didn't work.
const multer = require("multer");
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "./uploads/");
},
filename: (req, file, cb) => {
cb(null, new Date().toISOString() + file.originalname);
}
});
const fileFilter = (req, file, cb) => {
if (
file.mimetype === "image/jpeg" ||
file.mimetype === "image/png" ||
file.mimetype === "image/jpg"
) {
cb(null, true);
}
cb(null, false);
};
const upload = multer({
storage: storage,
limits: { fileSize: 5000000 },
fileFilter: fileFilter
});
// Create a post
router.post(
"/",
upload.single("image"),
passport.authenticate("jwt", { session: false }),
(req, res) => {
const { errors, isValid } = validationPostInput(req.body);
if (!isValid) {
return res.status(400).json(errors);
}
console.log(req.file);
const newPost = new Post({
text: req.body.text,
theme: req.body.theme,
name: req.body.name,
avatar: req.body.avatar,
image: req.file.path,
user: req.user.id
});
newPost.save().then(post => res.json(post));
}
);
// CREATE A POST
export const createPost = (userInput, history) => dispatch => {
const headers = {
"Content-Type": "form-data"
};
axios
.post("/post", userInput, headers)
.then(res => history.push("/post/all"))
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: err.response.data
})
);
};
import React, { Component } from "react";
import PropTypes from "prop-types";
// import { Link } from "react-router-dom";
import { connect } from "react-redux";
import { createPost } from "../../actions/postActions";
import "./style.css";
class CreatePost extends Component {
state = {
text: "",
theme: "",
image: "",
errors: {}
};
componentWillReceiveProps(nextProps) {
if (nextProps.errors) {
this.setState({ errors: nextProps.errors });
}
}
onSubmit = e => {
e.preventDefault();
const { user } = this.props.auth;
const newPost = {
text: this.state.text,
theme: this.state.theme,
image: this.state.image,
name: user.username,
avatar: user.avatar
};
this.props.createPost(newPost);
};
onChange = e => this.setState({ [e.target.name]: e.target.value });
fileSelectHandler = e => {
const param = e.target.files[0];
let reader = new FileReader();
reader.readAsDataURL(param);
this.setState({
image: reader.result
});
console.log(reader);
};
render() {
const { text, theme, errors } = this.state;
return (
<section className="post">
<form
onSubmit={this.onSubmit}
className="post__form"
action="/post"
method="POST"
encType="multipart/form-data"
>
<div className="post__form--input">
<label>Theme</label>
<input
type="text"
name="theme"
value={theme}
onChange={this.onChange}
/>
{errors && <small>{errors.theme}</small>}
</div>
<div className="post__form--input">
<label>Text</label>
<textarea
type="text"
name="text"
value={text}
onChange={this.onChange}
/>
{errors && <small>{errors.text}</small>}
</div>
<div className="post__form--file">
<label>Add Image</label>
<input
type="file"
name="file"
accept=".png, .jpg"
onChange={this.fileSelectHandler}
/>
</div>
<button type="submit" className="button">
Submit
</button>
</form>
</section>
);
}
}
CreatePost.propTypes = {
errors: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
errors: state.errors,
auth: state.auth
});
export default connect(
mapStateToProps,
{ createPost }
)(CreatePost);
Finally, I found out how to solve that problem.
onSubmit = e => {
e.preventDefault();
const { user } = this.props.auth;
const form = new FormData();
form.append("file", this.state.file);
form.append("theme", this.state.theme);
form.append("text", this.state.text);
form.append("name", user.username);
form.append("avatar", user.avatar);
this.props.createPost(form);
}
You are sending the field name as file:
<input
type="file"
name="file"
accept=".png, .jpg"
onChange={this.fileSelectHandler}
/>
But you are setting the field name as "image" on multer:
upload.single("image")
You need to change it to:
upload.single("file")
The correct syntax is:
.single(fieldname)
Accept a single file with the name fieldname. The single file will be
stored in req.file.

Resources