FormData not working with Axios Post request - MERN react Js - reactjs

I've been trying to make a post request to my server(Node Js+Mongodb which runs on localhost too). Axios.post works properly on the client code, however when i try to use formData it doesn't. I can't seem to find any reason why it's not working.
It leaves no error on the console(which makes it more frustrating).
Here is the client code:
someone pls point me to what I might be doing wrong.
import React, { useState } from 'react'
import Axios from 'axios'
export default function InputData() {
const [inputName, setInputName] = useState("")
const [inputAge, setInputAge] = useState(0)
const [inputEmail, setInputEmail] = useState("")
const [userImage, setUserImage] = useState("")
const [info,setInfo] = useState("")
var bodyFormData = new FormData();
bodyFormData.append('name', inputName);
bodyFormData.append('age', inputAge);
bodyFormData.append("email", inputEmail)
const createUser = () => {
Axios.post("http://localhost:3008/createUser",
bodyFormData , { headers: { 'Content-Type': 'multipart/form-data' } }).then(function (response) {
//handle success
console.log(response);
}).catch(function (response) {
//handle error
console.log(response);
});
}
return (
<div>
<form onSubmit={createUser} encType="multipart/form-data">
<div>
<input type="text" placeholder='enter name' value={inputName} width={400} onChange={(e) => setInputName(e.target.value)} /><br/>
<input type="number" placeholder='enter age' width={400} value={inputAge} onChange={(e) => setInputAge(e.target.value)} /><br/>
<input type="email" placeholder='enter e-mail' width={400} value={inputEmail} onChange={(e) => setInputEmail(e.target.value)} /><br />
<button>Submit</button>
</div>
</form>
</div>
)
}
axios: "^0.27.2",
react: "^18.2.0"

Couple of points:
You're probably not seeing any errors (output) in the console because you're submitting the form. You can change your onSubmit handler to include preventDefault:
const createUser = (e) => {
Axios.post("http://localhost:3000/createUser", bodyFormData, { headers: { 'Content-Type': 'multipart/form-data' } })
.then(console.log)
.catch(console.error);
e.preventDefault();
}
You can also keep it as is and see the previous output by persisting the logs of your browse across requests, in Firefox this checkbox:
You should add method=post to your form

I think you will receive all the data from the event [createUser method] on submitting the form, Try removing the header If you still have problem try as below, If you still have the problem check the server side Post method Params
let data = { name: inputName, age: inputAge, email: inputEmail }
Axios.post("http://localhost:3008/createUser",data )
.then(function (response) { console.log(response); })
.catch(function (response) { console.log(response); });

Related

Getting 404 Error Response in google chrome extension in React js frontend and express backend

I am trying to create a simple form handling experiment where it will put all fetched data from database and display it to user.
I am using 2 separate projects for frontend and backend.
Frontend is in react and backend is in express js.
Here is my express.js code
const express = require("express");
const monggose = require("mongoose");
const bodyParser = require("body-parser");
const { default: mongoose } = require("mongoose");
const cors = require("cors");
const { Router } = require("express");
const app = express();
app.use(cors());
app.use(bodyParser.urlencoded({ extended: true }));
// ================= Connectivity ========
monggose.set("strictQuery", false);
mongoose.connect("mongodb://127.0.0.1:27017/players");
const cricketerSchema = monggose.Schema({
rank: Number,
name: String,
country: String,
dob: Date,
totalRun: Number,
});
const Cricketer = monggose.model("cricketers", cricketerSchema);
// === GET ,POST, DELETE ========
app
.route("/cricketers")
.get(function (request, response) {
Cricketer.find(function (error, foundCricketers) {
if (!error) {
response.send(foundCricketers);
} else {
response.send(error);
}
});
})
.post(function (request, response) {
const c1 = new Cricketer({
// ==== here Rank is the name of the attribute of form field
rank: request.body.Rank,
// ==== here Nank is the name of the attribute of form field
name: request.body.Name,
country: request.body.Country,
dob: request.body.DOB,
totalRun: request.body.TotalRun,
});
c1.save(function (error) {
if (!error) {
console.log("Data inserted successfully");
response.send("Data added successfully...");
} else {
console.log(error);
response.send(error);
}
});
})
.delete(function (request, response) {
Cricketer.deleteMany(function (error) {
if (!error) {
response.send("All Data Deleted");
} else {
response.send(error);
}
});
});
app.listen(3010, function () {
console.log("Server is running at http://localhost:3010");
});
and here is my frontend code.
import { useEffect, useState } from "react";
import axios from "axios";
function App() {
const [name, setName] = useState("zain");
const [rank, setRank] = useState("5");
const [country, setCountry] = useState("india");
const [dob, setDOB] = useState("2023-02-21");
const [totalrun, setRun] = useState("5000");
const [cricketers, setCricketers] = useState([]);
const baseURL = "http://localhost:3010/cricketers";
useEffect(() => {
axios.get(baseURL).then((response) => {
const x = response.data;
setCricketers(x);
});
}, []);
function handlesubmit() {
const collection1 = {
Name: name,
Country: country,
DOB: dob,
TotalRun: totalrun,
Rank: rank,
};
console.log(collection1);
useEffect(() => {
axios
.post(baseURL, collection1)
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
});
}
return (
<div>
<label>Cricketer Rank:</label>
<input
type="number"
name="Rank"
value={rank}
onChange={(e) => setRank(e.target.value)}
/>
<br />
<label>Cricketer Name:</label>
<input
type="text"
name="Name"
value={name}
onChange={(e) => setName(e.target.value)}
/>
<br />
<label>Cricketer Country:</label>
<input
type="text"
name="Country"
value={country}
onChange={(e) => setCountry(e.target.value)}
/>
<br />
<label>Cricketer DOB:</label>
<input
type="date"
name="DOB"
value={dob}
onChange={(e) => setDOB(e.target.value)}
/>
<br />
<label>Cricketer TotalRun:</label>
<input
type="number"
name="TotalRun"
value={totalrun}
onChange={(e) => setRun(e.target.value)}
/>
<br />
<button onClick={handlesubmit}>Submit</button>
<ul>
{cricketers.map((i) => (
<li key={i._id}>
<p>
{i.name}
{i.country}
{i.rank}
{i.dob}
{i.totalrun}
</p>
</li>
))}
</ul>
</div>
);
}
export default App;
when page is loaded, it's fetching data from database and showing it into react page component.
For post method getting following error.
Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
at Object.throwInvalidHookError (react-dom.development.js:16227:9)
at useEffect (react.development.js:1634:21)
at handlesubmit (App.jsx:29:5)
My need is, I want to use functional component only and I have tried with all different solutions,
like fetch and axios.
It's not working.
When I am calling POST method from POSTMAN api it's working perfectly.
You are calling useEffect inside handleSubmit function. Hooks cannot be called inside a function. They can only be called at top level of a functional component. Refactor the handleSubmit function.
Please remove useEffect in your handleSubmit function. GET request must be put inside useEffect, but POST, PUT, PATCH,... don't. It all has to do with when the request is called. You can read further about useEffect to understand this.

Axios post request of form data send nothing

I need to send form data to my database with an Axios post request, but nothing is sent.
The data I need is what is in movieId input.
Maybe the formData.append is not well written ?
const { register, handleSubmit } = useForm();
const onSubmit = data => {
const formData = new FormData();
formData.append('movieId', data.movieId);
axios.post("http://localhost:5000/addMovie", formData)
.then(response => {
console.log("Status: ", response.status);
console.log("Data: ", response.data);
}).catch(error => {
console.error('Something went wrong!', error);
});
}
return (
<div id="ModalBackground">
<div id="ModalContainer">
<button id= "closeModal" onClick= {() => {closeModal(false)}}>X</button>
<h1 id= "formTitle">Numéro du film</h1>
<form onSubmit={handleSubmit(onSubmit)} id="addMovieForm">
<input type="text" id="movieId" {...register("movieId")} required></input>
<input id= "submit" type="submit" value="Ajouter !"></input>
</form>
</div>
</div>
);
}
export default Modal```
Something is wrong there, i saw you have something specific for the handle submit, so you need to cast your call differently. Because when you do directly onSubmit={handleSubmit(onSubmit)} you are calling directly this method on every render/update
<form onSubmit={handleSubmit(onSubmit)} id="addMovieForm"
<form onSubmit={() => handleSubmit(onSubmit)} id="addMovieForm">
// if you wish to cast the event aswell
<form onSubmit={e => handleSubmit(e,onSubmit)} id="addMovieForm">
I use react hook form (https://react-hook-form.com/get-started), and the doc say that :
const { register, handleSubmit, watch, formState: { errors } } = useForm();
const onSubmit = data => console.log(data);
console.log(watch("example")); // watch input value by passing the name of it
return (
/* "handleSubmit" will validate your inputs before invoking "onSubmit" */
<form onSubmit={handleSubmit(onSubmit)}>```
So I don't know what I have to do xD
Change onSubmit={handleSubmit(onSubmit)} to onSubmit={handleSubmit} as the former is supported in HTML but not in React.
<form onSubmit={handleSubmit} id="addMovieForm">
Add a name attribute to the input field so that the key value pair for this particular input field can be stored inside FormData. This eliminates the formData.append step inside handleSubmit().
<input type="text" id="movieId" name="movieId" required></input>
You need to specify Content-Type: multipart/form-data inside the header of the POST request.
const handleSubmit = (e) => {
e.preventDefault();
// Passing form element (e.target) populates the FormData object with the names and values of the fields inside it.
const formData = new FormData(e.target);
// formData.append("movieId", data.movieId);
// To check formData because simply console.log(formData) won't work
for (let item of formData) {
console.log(item);
}
axios
.post("http://localhost:5000/addMovie", formData, {
headers: { "Content-Type": "multipart/form-data" },
})
.then((response) => {
console.log("Status: ", response.status);
console.log("Data: ", response.data);
})
.catch((error) => {
console.error("Something went wrong!", error);
});
};

How to send a form input data containing both image and text from React front-end to Express backend using Multer

When I test sending a request containing both image and text grabbbed from user, it comes through to the backend with proper data when I use Postman. Not from React front-end, though. Request does come through but req.body seems to be empty when I console.log it from backend. What am I doing wrong? I am using Multer.
//FRONT-END
import React, { useState } from 'react';
import axios from 'axios';
const ListProperty = (props) => {
const [address, setAddress] = useState('');
const [file, setFile] = useState(null);
const [filename, setFilename] = useState('Choose File');
const handleAddressChange = (evt) => {
setAddress(evt.target.value);
};
const handlePhotoSelect = (evt) => {
setFile(evt.target.files[0]);
setFilename(evt.target.files[0].name);
};
const handleSubmit = async (evt) => {
evt.preventDefault();
const formData = new FormData();
formData.append('address', address);
formData.append('upload', file);
console.log(formData);
try {
axios.post('http://localhost:3000/listproperty', {
headers: { 'Content-Type': 'multipart/form-data' },
body: formData,
});
} catch (err) {
console.log(err);
}
};
return (
<div>
<h2>Property Listing Form</h2>
<span>Provide property address and Photo</span>
<form onSubmit={handleSubmit}>
<input
type="text"
value={address}
onChange={handleAddressChange}
name={address}
placeholder="Enter address"
/>
<br />
<input type="file" onChange={handlePhotoSelect} />
<button>Click to list</button>
</form>
</div>
);
};
export default ListProperty;
//BACK-END
const express = require('express');
const PropertyModel = require('../models/propertyModel');
const router = new express.Router();
const UserModel = require('../models/userModel');
const multer = require('multer');
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'public/images');
},
filename: function (req, file, cb) {
const uniqueName = `${Math.random().toString(32).slice(2)}.jpg`;
req.image = uniqueName;
cb(null, uniqueName);
},
});
const upload = multer({ storage });
router.post(
'/listproperty',
upload.single('upload'),
async (req, res) => {
console.log('hitting Backend router');
const property = new PropertyModel({
...req.body,
owner: req.user._id,
photo: req.image,
});
await UserModel.findByIdAndUpdate(req.user._id, {
$push: { properties: property._id },
});
try {
await property.save();
res.status(200).send(property);
} catch (err) {
console.log(err);
res.status(400).send(err);
}
}
);
module.exports = router;
If you are sending form data in the body you need to use the formidable npm module
you can install it using npm i formidable
then require formidable at top of the file
var formidable = require("formidable");
router.post(
'/listproperty',
upload.single('upload'),
async (req, res) => {
var form = new formidable.IncomingForm();
form.multiples = false;
form.parse(req, async function (err, fields, files) {
/**now here you can get all files in files and fields with fields
in your case you have sent
formData.append('address', address);
formData.append('upload', file);
above two data in form
so you can get your image from files.upload
and address fields.address **/
})
})
In addition, I would suggest you use Axios for api calls
your axios request is not right. axios post request accepts data as a second argument and third argument is for options ( headers etc ),
axios.post('http://localhost:3000/listproperty', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
});
another thing is your request is not being triggered at all. try setting input type to submit instead of using the button to trigger onSubmit handler of the form.
<form onSubmit={handleSubmit}>
<input
type="text"
value={address}
onChange={handleAddressChange}
name={address}
placeholder="Enter address"
/>
<br />
<input type="file" onChange={handlePhotoSelect} />
<input type="submit" value="Submit" />
</form>

React axios post request does not send the data

I am using react for my app. I am learning post request. I found one dummy api site Mocky where I can test my post request. This is my api link .For post request I used axios. I don't know how the Mocky api works. I made post request. when I console log the input values I can the value.But when I console log the response it seems like it does not get the data. I don't see any where I am making mistake.
Here is my code:
import React, { useState } from 'react';
import { API_URLS } from '../utilities';
import axios from "axios";
export default function CreateAccount() {
const [state, setState] = useState({
"email": ``,
"password": ``,
"loading": false,
"error": ``
});
const onChangeStudent = (e) => {
setState({
...state,
[e.target.id]: e.target.value
});
};
const onSubmit = async (e) => {
e.preventDefault();
console.log(state);
const url = `https://run.mocky.io/v3/15c2b7ec-9f31-4a18-ae60-a7f41e1f39b2`;
const obj = {
"email": state.email,
"password": state.password
};
console.log(obj.email); //I can see the input value
console.log(obj.password);//I can see the input value
axios
.post(url, obj)
.then((res) => {
console.log(res.data); // it does not show the data
console.log(res);
})
.catch((error) => {
setState({
...state,
"error": error
});
});
};
return (
<div>
<form onSubmit={onSubmit}>
<input
type="text"
value={state.name}
onChange={onChangeStudent}
id="email"
required
/>
<input
type="password"
value={state.password}
onChange={onChangeStudent}
id="password"
required
/>
<button
className="btn waves-effect blue lighten-1"
type="submit"
name="action"
disabled={state.loading}
>
{state.loading ? `loading...` : `save`}
</button>
</form>
</div>
);
}
Hi can't seem to find anything wrong with what you are doing.
I tested the below and it worked for me. Try to change from .then to await. Hope this solves your problem. Check in your network tab if your request is successful and if you are sending the body.
try {
const response = await axios.post('https://run.mocky.io/v3/4b95050f-2bcc-4c78-b86e-6cac09372dce', data);
console.log("Response", response);
} catch(e) {
console.error(e);
}

Having issues connecting to express backend with React

Trying to set up a register form using react and then sending the form to my express backed to create the user. The request is getting to the back-end but none of the form data is there.
When i console.log the request body and params, only an empty object gets returned
Here is my react register code
import React from 'react'
class Register extends React.Component {
state = {
name: "",
username: "",
password: ""
}
handleChange = event => {
const { name, value } = event.target
this.setState({[name]:value})
}
handleSubmit = event => {
event.preventDefault();
fetch("/api/register", {
method: "POST",
body: JSON.stringify(this.state)
})
.then((result)=> result.json())
.then((info) => { console.log(info); })
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<input type="text" name="name" value={this.state.name} placeholder="name" onChange={this.handleChange} />
<input type="text" name="username" value={this.state.username} placeholder="username" onChange={this.handleChange} />
<input type="password" name="password" value={this.state.password} placeholder="password" onChange={this.handleChange} />
<button>Register</button>
</form>
</div>
)
}
}
export default Register
Express code
const express = require("express"),
passport = require("passport"),
User = require("../models/user");
const router = express.Router({mergeParams: true});
// /api before this
router.post("/register", (req, res)=>{
const newUser = new User({
username: req.body.username,
name: req.body.name
});
User.register(newUser, req.body.password, (err, user)=>{
if(err) {
console.log(err);
}
passport.authenticate("local")(req, res, ()=>{
res.redirect("/user/" + user._id);
});
});
});
module.exports = router;
Now im getting a 400 bad request error and another error that says: register:1 Uncaught (in promise) SyntaxError: Unexpected token B in JSON at position 0
I would say that the url from the fetch action is not matching your express route
/api/register > /register
Try adding /api to the express route or remove from the fetch action
I also noticed your route is not returning anything.
You have to return something in the response object.
res.json(newUser);
router.post("/register", (req, res)=>{
const newUser = new User({
username: req.body.username,
name: req.body.name
});
// some code
return res.json(newUser);
});

Resources