I'm working on a file upload app and have run into an issue. When submitting to upload the file, I get a post 404 error in the console. The full code is here. I'm assuming that there's an issue in the file upload component but can't seem to understand the problem here.
FileUpload.js
import React, { useState } from "react";
import axios from "axios";
export const FileUpload = () => {
const [file, setFile] = useState("");
const [filename, setFilename] = useState("Choose File");
const [uploadedFile, setUploadedFile] = useState({});
const onChange = (e) => {
setFile(e.target.files[0]);
setFilename(e.target.files[0].name);
};
const onSubmit = async (e) => {
e.preventDefault();
const formData = new FormData();
formData.append("file", file);
try {
const res = await axios.post("/upload", formData, {
headers: {
"Content-Type": "multipart/form-data",
},
});
const { fileName, filePath } = res.data;
setUploadedFile({ filename, filePath });
} catch (err) {
if (err.response.status === 500) {
console.log("There was a problem with the server");
} else {
console.log(err.response.data.msg);
}
}
};
return (
<>
<form onSubmit={onSubmit}>
<div class="custom-file">
<input
type="file"
class="custom-file-input"
id="customFile"
onChange={onChange}
/>
<label class="custom-file-label" for="customFile">
{filename}
</label>
</div>
<input
type="submit"
value="Upload"
className="btn btn-primary btn-block mt-4"
/>
</form>
</>
);
};
Related
it redirects to an empty js file when logging in, not to the js file I wrote. Should I redirect in my database code?
////////////////
const client = require('../../db')
const express = require('express');
const app = express();
const cors = require("cors");
app.use(cors());
app.use(express.json()); //req.body
app.listen(2136, ()=>{
console.log("Sever is now listening at port 5000");
})
client.connect();
app.post("/login", async (req, res) => {
try {
const { email, password } = req.body;
const user = await client.query(
`SELECT * FROM users WHERE email=$1 AND password=$2`,
[email, password]
);
if (user.rows.length === 0) {
res.status(404).send("Kullanıcı adı veya şifre yanlış");
} else {
res.send("Kullanıcı adı veya şifre doğru");
}
}catch (err) {
response
.status(500)
.json({ message: "Error in invocation of API: /login" })
}
});
this is my database code.
///////////////////////
import {
BrowserRouter as Router,
Route
} from "react-router-dom";
import React, { useState } from 'react'
import Navbar from '../../common/Navbar/Navbar';
import AdminPage from './AdminPage';
const User = () => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [user, setUser] = useState([]);
const [error, setError] = useState('');
const onSubmitForm = async e => {
e.preventDefault();
try {
const response = await fetch(`http://localhost:2136/login`,{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password }),
});
console.log(email,password)
console.log(response);
if ((response.status)===404) {
setError('Invalid email or password');
} else
{
window.location.replace(`/AdminPage`);
}
} catch (err) {
console.error(error);
setError('An error occurred. Please try again later.');
}
};
return (
<>
<Navbar/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#4.4.1/dist/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous"></link>
<div className="container text-center">
<h1 className="my-5">Search for the Dormitory You Want</h1>
<form className="d-flex" onSubmit={onSubmitForm}>
<input
type="text"
name="name"
placeholder="Enter email ..."
className="form-control"
value={email}
onChange={e => setEmail(e.target.value)}
/>
<input
type="text"
name="name"
placeholder="Enter password ..."
className="form-control"
value={password}
onChange={e => setPassword(e.target.value)}
/>
<button className="btn btn-success">Submit
</button>
</form>
</div>
</>
)
}
export default User
this is my login page. the page it redirects to is a blank page. i don't understand why.
///////////////
import React, { useState } from 'react'
import AdminNavbar from '../../common/Navbar/AdminNavbar';
const AdminPage = () => {
return (
<>
<AdminNavbar/>
</>
);
}
export default AdminPage
and this the page I want to redirect AdminPage.So what can i do?
///////////////////
The difference between assign() and replace():
replace() removes the current URL from the document history.
With replace() it is not possible to use "back" to navigate back to the original document.
You can use assign method instead of location method
I've tried everything, I used the standard input, without success, I already changed the onSubmit to onClick, without success, I already put the function in the onClick button without success, it only works when I remove the input field of type file
I am using Electron React Boilerplate
https://github.com/electron-react-boilerplate/electron-react-boilerplate
import { Button, Pane, FileUploader, FileCard, Alert } from 'evergreen-ui';
import VideoSnapshot from 'video-snapshot';
import Input from 'renderer/components/Input';
import React from 'react';
import axios from 'axios';
import ContainerMenu from '../components/ContainerMenu';
const Admin = () => {
const [name, setName] = React.useState('');
const [genre, setGenre] = React.useState('');
const [path, setPath] = React.useState('');
const [preview, setPreview] = React.useState(null);
const [submitError, setSubmitError] = React.useState('');
const [progress, setProgress] = React.useState(0);
const [files, setFiles] = React.useState([]);
const [fileRejections, setFileRejections] = React.useState([]);
const handleChange = React.useCallback((files) => setFiles([files[0]]), []);
const handleRejected = React.useCallback(
(fileRejections) => setFileRejections([fileRejections[0]]),
[]
);
const handleRemove = React.useCallback(() => {
setFiles([]);
setFileRejections([]);
}, []);
const handleSubmit = async (e) => {
e.preventDefault();
setSubmitError('');
if (files.length === 0) {
setSubmitError('O arquivo não pode ser vazio');
return;
}
try {
const snapshoter = new VideoSnapshot(files[0]);
const previewSrc = await snapshoter.takeSnapshot();
if (previewSrc) setPreview(previewSrc);
} catch (error) {
console.log(error);
}
try {
// const previewData = new FormData();
// const previewObject = {
// preview: previewSrc,
// };
// previewData.append('file', previewObject);
// await axios.post('http://localhost:3000/api/upload', previewData);
const formData = new FormData();
formData.append('file', files[0]);
formData.append('name', name);
formData.append('genre', genre);
formData.append('path', 'videos');
const response = await axios.post(
'http://localhost:3000/api/upload',
formData,
{
onUploadProgress: (progressEvent) => {
const progress = (progressEvent.loaded / progressEvent.total) * 50;
setProgress(progress);
},
}
);
} catch (error) {
console.log(error);
setSubmitError(error.message);
}
};
return (
<div>
<ContainerMenu />
<div className="container">
<form
encType="multpart/form-data"
className="form-group"
onSubmit={handleSubmit}
>
<h2>Enviar Arquivos</h2>
<br />
<div>
<Input
type="text"
label="Nome"
placeholder="Nome ..."
onChange={setName}
value={name}
/>
</div>
<div>
<Input
type="text"
label="Gênero"
placeholder="Gênero ..."
onChange={setGenre}
value={genre}
/>
</div>
<div>
<Pane>
<FileUploader
label="Upload File"
description="You can upload 1 file. File can be up to 50 MB."
maxSizeInBytes={50 * 1024 ** 2}
maxFiles={1}
onChange={handleChange}
onRejected={handleRejected}
renderFile={(file) => {
const { name, size, type } = file;
const fileRejection = fileRejections.find(
(fileRejection) => fileRejection.file === file
);
const { message } = fileRejection || {};
return (
<FileCard
key={name}
isInvalid={fileRejection != null}
name={name}
onRemove={handleRemove}
sizeInBytes={size}
type={type}
validationMessage={message}
/>
);
}}
values={files}
/>
</Pane>
</div>
<div>
<Button
isLoading={progress > 0 && progress < 100}
marginRight={16}
appearance="primary"
type="submit"
>
Enviar {progress.toFixed(2)}%
</Button>
</div>
<br />
<div>{preview && <img src={preview} alt="preview" />}</div>
<br />
<div>
{submitError.length > 0 && (
<Alert intent="danger" title="Error">
{submitError}
</Alert>
)}
</div>
</form>
</div>
</div>
);
};
export default function App() {
return <Admin />;
}
I am using React and trying to send the form Input as well as a image file to a express server at a same time. I tried by appending these inputs data and file to the formData() and sending it to backend through axios post request, but the problem is : The form input given by user is perfectly going to express server but file is undefined in backend
My JSX
<form onSubmit={sendData}>
<input value={data.productName} onChange={handleChange} type="text" name="productName" />
<input value={data.productfeatures} onChange={handleChange} type="text" name="productfeatures" />
<input onChange={imgChnage} type="file" name="test_files" />
<button>Submit</button>
</form>
My function to handle input
const [data, setData] = useState({
productName: "",
productfeatures: "",
})
const { productName, productfeatures } = data;
const [imgHolder, setImgHolder] = useState();
const handleChange = (evt) => {
const value = evt.target.value;
setData({
...data,
[evt.target.name]: value
});
}
const imgChnage = (e) => {
setImgHolder(e.target.files[0]);
};
console.log(imgHolder);
const sendData = async (e) => {
e.preventDefault();
const fd = new FormData();
fd.append('name', productName);
fd.append('features', productfeatures);
fd.append('image', imgHolder);
try {
await axios
.post("http://localhost:3001/pnit/v1/api/product", fd)
} catch (error) {
console.log(error);
}
All combined code
import { useState } from "react";
import axios from "axios";
function App() {
const [data, setData] = useState({
productName: "",
productfeatures: "",
})
const { productName, productfeatures } = data;
const [imgHolder, setImgHolder] = useState();
const handleChange = (evt) => {
const value = evt.target.value;
setData({
...data,
[evt.target.name]: value
});
}
const imgChnage = (e) => {
setImgHolder(e.target.files[0]);
};
const sendData = async (e) => {
e.preventDefault();
const fd = new FormData();
fd.append('name', productName);
fd.append('features', productfeatures);
fd.append('image', imgHolder);
try {
await axios
.post("http://localhost:3001/pnit/v1/api/product", fd)
} catch (error) {
console.log(error);
}
}
return (
<>
<form onSubmit={sendData}>
<input value={data.productName} onChange={handleChange} type="text" name="productName" />
<input value={data.productfeatures} onChange={handleChange} type="text" name="productfeatures" />
<input onChange={imgChnage} type="file" name="test_files" />
<button>Submit</button>
</form>
</>
);
}
export default App;
Hello developers, the problem is solved !!
Steps to solve a problem :
install the dependency called express-fileupload inside server by the command npm i express-fileupload.
import the express-fileupload at the main file of server.
And finally, call the middleware app.use(fileupload());
Why the problem occured !:
Because, by default the req.files is undefined but calling the middleware at server, it parse the req.files and shows up the files sent from frontend.
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}
Hii i ma new in reactjs i am getting an error when i am trying to add movie , everything i wrote correctly . but dont know why this error came anyone explain and help to solve error
this img help you to catch error easily
img
https://ibb.co/bW5t0t8 and
https://ibb.co/Ky7MQgw
env REACT_APP_BACKEND=http://localhost:8000/api
export const API = process.env.REACT_APP_BACKEND;
adminapicall.js
this is my all api call where i communicate with backend
import {API} from '../backend';
//add movie
export const addMovie = (userId,token,movie)=>{
return fetch(`${API}/movie/addMovie/${userId}`,{
method : "POST",
headers:{
Accept:'Application/json',
Authorization: `Bearer ${token}`
},
body:movie
}).then(response => {
return response.json()
})
.catch(err => console.log(err))
}
//get all movie
export const getAllMovies = () => {
return fetch(`${API}/movies`,{
method : "GET"
})
.then(response => {
return response.json();
})
.catch(err => console.log(err))
}
//get a movie
export const getMovie = movieId =>{
return fetch(`${API}/movie/${movieId}`,{
method : "GET"
})
.then(response => {
return response.json();
})
.catch(err => console.log(err))
}
//update movie
export const updateMovie = (movieId,userId,token,movie)=>{
return fetch(`${API}/movie/${movieId}/${userId}`,{
method : "PUT",
headers:{
Accept:'Application/json',
Authorization: `Bearer ${token}`
},
body:movie
}).then(response => {
return response.json()
})
.catch(err => console.log(err))
}
//delete movie
export const deleteMovie = (movieId,userId,token)=>{
return fetch(`${API}/movie/${movieId}/${userId}`,{
method : "DELETE",
headers:{
Accept:'Application/json',
Authorization: `Bearer ${token}`
}
}).then(response => {
return response.json()
})
.catch(err => console.log(err))
}
add Movie.js
here i wrote my all addmovie logic
import React,{useState} from 'react';
import Navbar from '../pages/Navbar';
import Footer from '../pages/Footer';
import {Link} from 'react-router-dom';
import {isAuthenticated} from '../Auth/index';
import {addMovie} from '../Admin/adminapicall';
const AddMovie = () => {
const {user,token} = isAuthenticated();
const [values,setValues] = useState({
movie_name:'',
actor:'',
country_of_origin:'',
duration:'',
director:'',
photo:'',
loading:false,
error:'',
addedMovie:'',
getRedirect:false,
// formData:''
})
const {movie_name,actor,country_of_origin,duration,director,photo,loading,error,addedMovie,getRedirect} = values;
const handleChange = name => event => {
const value = name === "photo" ? event.target.files[0] : event.target.value
// formData.set(name,value);
setValues({...values,[name]:value})
};
const onSubmit = (e) => {
e.preventDefault();
setValues({...values,error:'',loading:true})
addMovie(user._id,token,JSON.stringify(values)).then(data =>{
if(data.error){
setValues({...values,error:data.error})
}else{
setValues({
...values,
movie_name:'',
actor:'',
country_of_origin:'',
duration:'',
director:'',
photo:'',
loading:false,
addedMovie: data.movie_name
})
}
})
}
const successMessage = () => (
<div className='alert alert-success mt-3'
style={{display : addedMovie ? '' : 'none'}}>
<h4>{addedMovie} added successfully</h4>
</div>
)
// const successMessage = () => {
// }
const addMovieForm = () => (
<form >
<span>Post photo</span>
<div className="form-group">
<label className="btn btn-block btn-success">
<input
onChange={handleChange("photo")}
type="file"
name="photo"
accept="image"
placeholder="choose a file"
/>
</label>
</div>
<div className="form-group">
<input
onChange={handleChange("movie_name")}
name="photo"
className="form-control"
placeholder="movie_name"
value={movie_name}
/>
</div>
<div className="form-group">
<input
onChange={handleChange("actor")}
name="photo"
className="form-control"
placeholder="actor"
value={actor}
/>
</div>
<div className="form-group">
<input
onChange={handleChange("duration")}
type="number"
className="form-control"
placeholder="duration"
value={duration}
/>
</div>
<div className="form-group">
<input
onChange={handleChange("country_of_origin")}
type="text"
className="form-control"
placeholder="country_of_origin"
value={country_of_origin}
/>
</div>
<div className="form-group">
<input
onChange={handleChange("director")}
type="text"
className="form-control"
placeholder="director"
value={director}
/>
</div>
<button type="submit" onClick={onSubmit} className="btn btn-success mb-2">
Add Movie
</button>
</form>
);
return (
<div>
<Navbar/>
<div className='container'style={{height:'0px'}}>
<Link to='/admin/dashboard'> <h1 className=' bg-info text-white p-4 text-decoration-none'>Admin Home</h1> </Link>
<div className='row bg-dark text-white rounded'>
<div className='col-md-8 offset-md-2'>
{successMessage()}
{addMovieForm()}
</div>
</div>
</div>
<Footer/>
</div>
)
}
export default AddMovie;
backend
addmovie.js
this is my backend addmovie logic
const Movie = require('../model/movie');
const formidable = require('formidable');
const_ = require('lodash');
const fs = require('fs');
exports.getMovieById = (req, res, next, id) => {
Movie.findById(id).exec((err, movie) => {
if (err) {
return res.status(400).json({
error: "Movie not found "
})
}
req.movie = movie;
next();
})
}
exports.addMovie = (req, res) => {
let form = new formidable.IncomingForm(); // declare a form
form.keepExtensions = true;
form.parse(req, (err, fields, file) => { //parse the form like err,fields,file
if (err) {
return res.status(400).json({
error: "Problem with image"
})
}
//destructure the field
const {movie_name,actor,country_of_origin,duration,director } = fields;
if (!movie_name || !actor || !country_of_origin || !duration || !director)
{
return res.status(400).json({
error: "please include all fields"
})
}
let movie = new Movie(fields);
//handle file here
if (file.photo) {
if (file.photo.size > 300000) {
return res.status(400).json({
error: "file size to big!"
})
}
movie.photo.data = fs.readFileSync(file.photo.path)
movie.photo.contentType = file.photo.type;
}
//save to the database
movie.save((err, movie) => {
if (err) {
res.status(400).json({
error: "saving movie in database failed"
})
}
res.json(movie);
})
})
}
I believe Backend is working properly
In fetch when you are sending body you must send it in string format, it seems a movie variable is an object, convert it to string and send
return fetch(`${API}/movie/addMovie/${userId}`,{
method : "POST",
headers:{
Accept:'Application/json',
Authorization: `Bearer ${token}`
},
body:JSON.stringify(movie)
}).then(response => {
Do this changes in all your fetch calls