Param values are undefined during axios file upload along with text upload using FormData - reactjs

I'm building a simple books management application. In a particular page, I need to upload a book's details along with a picture of the book.
I'm using formData and axios to do this. In the same request, sending the optional image as well as the text inputs.
But on reading the text fields from the body in the server side, all of them are undefined.
How can I resolve this issue ?
addBooksForm.js
import { useContext, useState } from "react";
import { useNavigate } from "react-router-dom";
import "./addbooksform.css";
import axios from "axios"
import { authContext } from "../../App";
const Addbooks = () => {
// eslint-disable-next-line
const [authDet, setAuthDet] = useContext(authContext);
const navigate = useNavigate()
const [values, setValues] = useState({
title: "",
author: "",
genreId: 1,
price: 0,
picture:null
});
const handleSubmit = async (e) => {
e.preventDefault();
let data = new FormData()
data.set("title", values.title)
data.set("author", values.author)
data.set("genreId", values.genreId)
data.set("price", values.price)
data.set("picture", values.picture)
console.log(values)
const response = await axios.post("http://localhost:5000/api/books/",data,
{
headers:{
Authorization:`Token ${authDet.accessToken}`
}
})
if (response.status === 200) {
navigate('/yourbooks');
} else {
console.log("Error occurred "+ response)
}
};
const onChange = (e) => {
setValues({ ...values, [e.target.name]: e.target.value });
};
const onFileChange = (e) => {
setValues({...values, [e.target.name] : e.target.files[0] })
}
return (
<div className="addbooks">
<form onSubmit={handleSubmit}>
<h3>Title</h3>
<input type="text" name="title" required={true} onChange={onChange} value={values.title}/>
<h3>Author</h3>
<input type="text" name="author" required={true} onChange={onChange} value={values.author}/>
<h3>Genre</h3>
<input type="number" name="genreId" required={true} onChange={onChange} value={values.genreId}/>
<h3>Price</h3>
<input type="number" name="price" required={true} onChange={onChange} value={values.price}/>
<h3>Upload picture</h3>
<input type="file" name="picture" onChange={onFileChange}/>
<button>Add</button>
</form>
</div>
);
};
export default Addbooks;
I have also tried adding content-type:multipart/form-data in the config
Server side controller:
const addBooks = (e) => {
const { title, author, price, genreId } = req.body;
// further processing
}
here, all the fields are undefined
server.js:
app.use(express.urlencoded({extended:true}))
app.use(express.json())
app.use(cors())
Any help is appreciated. thanks in advance !!

Related

inputbox onchange event is not updating state in React JS

I'm learning React JS and trying to create a CRUD app. In a form, I could able to successfully fetch existing data and bind into forms controls. However, the onchange event of an input box does not seem to update the corresponding state. Sharing the code sample. Any input is highly appreciated.
import { useState, useEffect } from "react";
import { useParams } from "react-router-dom";
import { useNavigate } from "react-router-dom";
function BookEdits() {
const navigate = useNavigate();
const [data, setData] = useState("");
const [title, setTitle] = useState("");
const params = useParams();
// Please ignore this part
const handleSubmit = (event) => {
event.preventDefault();
const requestOptions = {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
title: title,
description: description,
author: author,
}),
};
fetch(`https://localhost:7174/api/books/${params.id}`, requestOptions).then(
(response) => {
console.log(response);
if (!response.ok) alert("Error saving book details");
else alert("Book details is saved successfully");
navigate("/BooksList");
}
);
};
//
useEffect(() => {
fetch(`https://localhost:7174/api/Books/${params.id}`)
.then((response) => response.json())
.then(setData);
}, []);
// Does not change post onchange event
console.log(data.title);
return (
<form onSubmit={handleSubmit}>
<label>
Title:
<input type="submit" />
</form>
);
<input
type="text" value={data.title}
onChange={(e) => setTitle(e.target.value)}
/>
</label>
<input type="submit" />
</form>
);
}
export default BookEdits;
State should update post onchange event. What am I missing here? Thanks in advance.
data.title isn't the same as title. You call setTitle, which changes title, but you're logging data.title, which isn't the same attribute.

Sending Form Data From Frontend to Backend Using Axios Using React

I am trying to get input from the user in a form field and access the data in my backend server.js . I wanted to use this data in order to pass parameters to the Yelp Fusion API I am using. I know I can use axios for this but am unsure how to accomplish this at this time.
Here is my server.js:
const express = require('express')
const dotenv = require('dotenv').config()
const port = process.env.PORT || 5000
var axios = require('axios');
const app = express()
var cors = require('cors');
app.use(cors());
// app.get('/', (req, res) => {
// var config = {
// method: 'get',
// url: 'https://api.yelp.com/v3/businesses/search?location=Houston',
// headers: {
// 'Authorization': 'Bearer <API_KEY>
// }
// };
// axios(config)
// .then(function (response) {
// //const data = JSON.stringify(response.data);
// res.json(response.data)
// })
// .catch(function (error) {
// console.log(error);
// });
// })
app.listen(port, () => console.log(`Server started on port ${port}`))
Here is the App.js in which I need to pass the state from the input field to the backend:
import React,{useEffect,useState} from 'react';
import './App.css';
import axios from 'axios'
function App() {
const [zip,setZip] = useState("")
function handleSubmit() {
useEffect(() => {
axios.post("http://localhost:8000")
.then(res => {
console.log(res)
})
})
}
// const [results, setResults] = useState({})
// console.log(results)
// useEffect(() => {
// axios.get('http://localhost:8000').then(res => {
// console.log(res)
// })
// }, [])
return (
<div>
<form onSubmit={handleSubmit}>
<label>
Name:
<input type="text" name="name" />
</label>
<input type="submit" value="Submit" />
</form>
</div>
);
}
export default App;
Ok, here's what's wrong with your code:
hooks can only be placed on the first level of functional component (outside any sub-functions) and must be before any return statements.
Use effect will fire on render, in your code it looks like you wanna trigger it on event click.
I would do it this way if I were you:
function App() {
const [zip,setZip] = useState("");
const triggerAPI = useCallback(async () => {
// Use async await instead of chained promise
const res = await axios.post("http://localhost:8000", { zip: zip });
console.log(res)
}, [zip]);
const handleSubmit = useCallback((e) => {
e.preventDefault()
triggerAPI();
}, [triggerAPI])
const handleChange = useCallback((event) => {
setZip(event.target.value);
}, []);
return (
<div>
<form onSubmit={handleSubmit}>
<label>
ZIP:
<input type="text" value={zip} name="zip" onChange={handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
</div>
);
}
export default App;
changes:
I used useCallback to memoize the functions
I used async/await instead of chained promise (looks cleaner)
You use useEffect() function wrongly.
Handle the input element state properly.
To send data to the server you can use axios.post(url,data).then()
import React, { useState } from "react";
import axios from "axios";
function App() {
const [zip, setZip] = useState("");
function handleSubmit(event) {
event.preventDefault();
axios.post("http://localhost:8000", { zip: zip }).then((res) => {
console.log(res);
});
}
const handleChange = (event) => {
setZip(event.target.value);
};
return (
<div>
<form onSubmit={handleSubmit}>
<label>
ZIP:
<input type="text" value={zip} name="zip" onChange={handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
</div>
);
}
export default App;

Heroku not running like it should after trying to post data i get a json object loading instead of a page

I'm having problems with heroku. After i try to post data (post a listing), instead of being redirected to listings page where you would find a listing I just posted (that's how it works when i run it locally), the page displays a json object. And refresh doesn't work, i need to type the address again and then everything works normally, and the listing that i just posted is there as it should.
This is the front end
import { useState } from 'react'
import axios from 'axios'
import { useNavigate } from 'react-router-dom'
const PostListings = () => {
let navigate = useNavigate()
const [ newList, setNewListing ] = useState({
city: '',
neighborhood: '',
bedrooms: '',
price: '',
img: '',
reviews_id: []
})
const getNewListing = async () => {
console.log(newList)
await axios({
url: `${window.location.origin}/listings`,
method: 'post',
data: newList
})
}
const handleChange = (e) => {
setNewListing({...newList, [e.target.name]: e.target.value })
console.log(e.target.name)
console.log(e.target.value)
console.log(newList)
}
const handleSubmit= () => {
getNewListing()
navigate('/listings')
window.location.reload(false)
}
return (
<div>
<h2>Add A New Listing</h2>
<form className="submit-form" onSubmit={handleSubmit}>
<input type="text" value={newList.city} onChange={handleChange} name={'city'} placeholder={'city'} />
<input type="text" value={newList.neighborhood} onChange={handleChange} name={'neighborhood'} placeholder={'neighborhood'} />
<input type="text" value={newList.img} onChange={ handleChange} name={'img'} placeholder={'image'} />
<input type="text" value={newList.price} onChange={ handleChange} name={'price'} placeholder={'price'} />
<input type="text" value={newList.bedrooms} onChange={ handleChange} name={'bedrooms'} placeholder={'bedrooms'} />
<button>Submit</button>
</form>
</div>
)
}
export default PostListings
//this is in Controllers
const postListing = async (req, res) => {
try {
console.log('data:', req.body)
const listing = await new Listing(req.body)
console.log('new:', listing)
await listing.save()
return res.status(201).json({ listing })
} catch (error) {
return res.status(500).json({ error: error.message })
}
}
//and in index.js
app.post('/listings', listingsController.postListing)

How to save values sent via post request in redux-toolkit async thunk

I'm making a react component which has two input fields.One have the key : type,another the key: range.The problem is that when i submit the data i dont know how to save it as an array or something,to stack more pairs of information,because i need to display a progress bar based on the information from the input field. Could you help me please?
Here is my Slice:
export const skillSlice = createSlice({
name: "skill",
initialState: {
name:'',
range:null
},
reducers: {
setSkill: (state, action) => {
console.log("action", action.payload);
state.name = action.payload?.name;
state.range = action.payload?.range;
}
}
});
export const addNewSkill = createAsyncThunk(
'skills/addNewSkill',
async (_,{rejectWithValue,dispatch}) =>{
try{
const response = await fetch('/api/skills',{
method:'POST',
headers:{
'Content-name' : 'application/json',
},
});
if(!response.ok){
throw new Error('Can\'t add skill. Server error')
}
const data = await response.json();
dispatch(setSkill(data))
}catch(error){
return rejectWithValue(error.message);
}
}
)
export const fetchSkills = createAsyncThunk(
'skills/fetchSkills',
async (_, {rejectWithValue}) => {
try{
const response = await fetch('/api/skills',{
method:'GET',
})
// console.log(response)
if(!response.ok){
throw new Error ('Server Error!');
}
const data = await response.json();
// console.log(data)
return data;
} catch(error){
return rejectWithValue(error.message);
}
}
);
const { setSkill } = skillSlice.actions;
export const selectSkill = (state) => state?.skill;
export default skillSlice.reducer;
And here is the component:
import React, { useState,useEffect } from 'react'
import { Formik, Form, useFormik } from 'formik'
import * as Yup from 'yup'
import FormikControl from '../Form/FormikControl'
import DisplayFormikState from '../Form/DisplayFormikState.js'
import { useDispatch, useSelector } from 'react-redux'
import { addNewSkill,fetchSkills,selectSkill } from '../../features/skills/skillSlice'
const Skills = () =>{
const dispatch = useDispatch();
const [skill, setSkills] = useState({
name: '',
range: null
});
useEffect(()=>{
dispatch(fetchSkills());
},[dispatch])
const userInfo = useSelector(selectSkill);
const skillList = useSelector(state => state.skillState)
const { status, error } = useSelector(state => state.skillState)
const handleChange = (e) => {
const { name, value } = e.target;
setSkills({ ...skill, [name]: value });
};
const handleSubmit = (e) => {
e.preventDefault();
dispatch(addNewSkill(skill));
};
const formik = useFormik({
// initialValues:{
// name: skill.name,
// range: skill.range
// },
validationSchema:Yup.object({
}),
})
return(
<>
<section id="skills">
<h1 className='SkillSection'>Skills</h1>
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="type">Type</label>
<input
id='type'
name='name'
type='text'
placeholder='Enter skill name'
onChange={handleChange}
// value={formik.values.name}
/>
</div>
<div>
<label htmlFor="level">Level</label>
<input
id='level'
type='text'
name='range'
placeholder='Enter range'
onChange={handleChange}
// value={formik.values.range}
/>
</div>
<button type='submit'>Submit</button>
</form>
</section>
</>
)
}
export default Skills
In the above code the initial state isn't an array because when i tried to push values to it i got undefined,so,i left the working state not to get confused. Thanks in advance!

React "undefined" when posting with axios

Hello im trying to push some data to my API with axios and react but i keep getting undefined. i cant find my error what am i doing wrong would appreciate some help.
im using 2 components one to handle the inputs which seem to work i can see the fields filled with data
import { useState } from 'react'
export const useForm = (initialValues) => {
const [values, setValues] = useState(initialValues);
return [
values,
e => {
setValues({
...values,
[e.target.name]: e.target.values
});
}
]
}
and the component where do my API CALL
import "../Admin/admin.css";
import Axios from "axios";
import { useForm } from "./useForm";
// Displays booking with a person added.
const AddBookableTime = () => {
const [values, handleChange] = useForm({ startTime: '', endTime: '' })
const API_ENDPOINT = "https://localhost:44387/api/BookableHours";
const PostBookingTimes = async (e) => {
e.preventDefault()
let times = createBookingTimes(e);
try {
await Axios.post(`${API_ENDPOINT}`, times);
} catch (err) {
}
};
//Creating object to send to api
const createBookingTimes = (e) => {
let bookableHours = {
startTime: e.target.values.startTime,
endTime: e.target.values.endTime,
};
return bookableHours;
};
return (
<>
<form onSubmit={(e) => PostBookingTimes(e)}>
<input type="text" name="startTime" value={values.startTime} onChange={handleChange} ></input>
<input type="text" name="endTime" value={values.endTime} onChange={handleChange} ></input>
<button type="submit" value="Post" className="booking-button">
Lägg till ny bokningsbar tid
</button>
</form>
</>
);
}
export default AddBookableTime;

Resources