Cloudinary return empty url on first try - reactjs

It is strange that whenever I restart the ReactJS and click on postDetails, it always returns an empty URL, and if I click again it returns the URL path of the image. Am I missing something in this code here. many thanks in advance and greatly appreciated.
const Addpost = () => {
const [photo, setPhoto] = useState("")
const [photoURL, setPhotoURL] = useState("")
const postDetails = () => {
const data = new FormData()
data.append("file", photo)
data.append("upload_preset", "xxxxx")
data.append("cloud_name", "xxxxx")
fetch("https://api.cloudinary.com/v1_1/xxxxx/image/upload",{
method: "POST",
body: data
})
.then(res => res.json())
.then((data) => {
setPhotoURL(data.url)
})
.catch(err => {
console.log(err)
})
}
return (
<React.Fragment>
<input
type="file"
className="form-control-file"
id="photo"
name="photo"
onChange={(e) => setPhoto(e.target.files[0])}
/>
<button
type="submit"
className="btn btn-primary btn-block"
onClick={postDetails}
>
Submit
</button>
</React.Fragment>
)
}

try to do async await then (setPhotoUrl() will only be updated once the fetch get something or console.log('No data fetched!')):-
const postDetails = async() => {
const data = new FormData()
data.append("file", photo)
data.append("upload_preset", "xxxxx")
data.append("cloud_name", "xxxxx")
let res = await fetch("https://api.cloudinary.com/v1_1/xxxxx/image/upload",{
method: "POST",
body: data
})
if(!res) console.log('No data fetched!')
let data = res.json()
setPhotoURL(data.url)
}

Related

Mulitple image add in react js

I am working on a project where I have one page where you should be able to add images. One by one it's worked perfectly. Now I want to make to be able to multiple add and upload. I don't want to use any library for image upload.
const onFileChange = (e) => {
const reader = new FileReader();
reader.onload = () => {
if (reader.readyState === 2) {
setPreview(reader.result);
}
};
reader.readAsDataURL(e.target.files[0]);
if (e.target.files[0]) {
setOver(true);
}
const copy = [...image];
copy.push(e.target.files[0]);
setImage([...copy]);
};
const onFileUpload = () => {
const formdata = new FormData();
image.forEach((elem) => {
formdata.append("data", elem);
});
formdata.append("id_grobnog_mjesta", Id);
addImage(formdata);
};
const addImage = async (data) => {
try {
setIsLoading(true);
const response = await apiRequest({
method: "post",
url: `spisak-srebrenica/upload`,
headers: {
Authorization: `Bearer ${token}`,
},
data,
});
if (response.data.success) {
getVictimImage();
}
setIsLoading(false);
setImage([]);
} catch (err) {
setIsLoading(false);
setImage([]);
}
};
Upload component :
<Upload>
<BiImageAdd size={50} opacity={0.5} />
<input type="file" onChange={onFileChange} />
<div className="items">
<p>Dodajte sliku</p>
<span className="format">PNG,JPG,GIF do 10MB</span>
</div>
</Upload>
add multiple attribute
<input type="file" id="files" name="files" multiple>
https://www.w3schools.com/tags/att_input_multiple.asp

Why does my upload to Cloudinary works but does not update the database?

I'm trying to upload a file to Cloudinary and save this file to a MongoDb database. The upload is working (I can see the new image in my Cloudinary account), but the db is not updated. The back end is built with Express. This is my code:
React function:
const { user, updateUser } = useContext(AuthContext)
const [imageUrl, setImageUrl] = useState("")
const navigate = useNavigate()
useEffect(() => {
axios
.get(`${API_URL}/users/user/${user._id}`)
.then(response => {
const { imageUrl } = response.data
setImageUrl(imageUrl)
})
.catch(err => console.log(err))
}, [user._id])
const handleFileUpload = e => {
e.preventDefault()
const uploadData = new FormData()
uploadData.append("imageUrl", e.target.files[0])
service
.uploadImage(uploadData)
.then(res => {
setImageUrl(res.secure_url)
})
.catch(err => console.log(err))
}
const handleSubmit = e => {
e.preventDefault()
const requestBody = { imageUrl }
if (imageUrl === "") {
return
}
axios
.put(`${API_URL}/users/edit-picture/${user._id}`, requestBody)
.then(res => {
updateUser(res.data)
navigate("/my-account")
})
.catch(err => console.log(err))
}
JSX:
<Form
onSubmit={handleSubmit}
>
<Input
type="file"
id="imageUrl"
onChange={handleFileUpload}
/>
<Button type="submit">Send</Button>
</Form>
updateUser function:
const updateUser = updatedUser => {
localStorage.setItem("user", JSON.stringify(updatedUser))
setUser(JSON.parse(localStorage.getItem("user")))
}
uploadImage function:
const uploadImage = file => {
return axios
.put(`${API_URL}/users/upload-picture`, file)
.then(res => res.data)
.catch(errorHandler)
}
And for the backend (where fileUploader is the Cloudinary config file):
router.put(
"/upload-picture",
fileUploader.single("imageUrl"),
(req, res, next) => {
if (!req.file) {
next(new Error("No file uploaded"))
return
}
res.json({ secure_url: req.file.path })
}
)
router.put("/edit-picture/:id", (req, res, next) => {
const { imageUrl } = req.body
const id = req.params.id
console.log(id)
User.findByIdAndUpdate(id, { imageUrl }, { new: true })
.then(updatedUser => {
res.status(200).json(updatedUser)
})
.catch(err => next(err))
})
Thanks for your help!
There seems to be some issue with your mongodb connection
Check wheather you are running mongodb locally and is it working properly
Check the mongodb URL that you would have used in express.Before integrating with react..check the API in postman or some other testing tool.

SyntaxError: Unexpected token < in JSON at position 0 while doing api post request in reactjs

I am trying to send form data and do a post request on API and get predictions but I am getting the error SyntaxError: Unexpected token < in JSON at position 0 while doing. I have checked the API and it is perfectly fine. I have attached the post request below. I was guessing there is a problem with forms. please correct me if I am wrong.
const FirstProject = () => {
const [solutestate, setSoluteState] = useState("");
const [solventstate, setSolventState] = useState("");
const [fetchData, setFetchData] = useState("");
const [Error, setError] = useState(null);
const { register, handleSubmit, control } = useForm({
defaultValues: {
solute: "",
solvent: "",
},
});
const formData = new FormData();
const onSubmit = (data) => {
formData.set("solute", data.solute);
formData.set("solvent", data.solvent);
fetch("https://flask-api-test1.herokuapp.com/predict", {
method: "post",
body: formData,
})
.then((res) => res.json())
.then((result) => {
setFetchData(result.result.predictions);
//console.log(result.result.predictions);
//console.log(Object.entries(result));
// setIsPending(false);
})
.catch((err) => {
console.log(data);
setError(err.error);
console.log(err);
});
};
<form onSubmit={handleSubmit(onSubmit)}>
<input
{...register("solute")}
placeholder="First Name"
onChange={(e) => setSoluteState(e.target.value)}
value={solutestate}
/>
<input
{...register("solvent")}
placeholder="First Name"
onChange={(e) => setSolventState(e.target.value)}
value={solventstate}
/>
<input type="submit" />
</form>
The json() method of the Response interface takes a Response stream and reads it to completion. It returns a promise which resolves with the result of parsing the body text as JSON, but your request for API return 500 status code. You can handle it like this:
.then((res) => {
if (res.ok) {
return res.json();
}
throw "Something went wrong";
})
instead of
.then((res) => res.json())

Image upload in mern stack using multer not working

I'm trying to upload image in MongoDB using multer and react but I'm unable to post it. I have three inputs in by form i.e title, content and image. If I try to post title and content only it is successfully being posted. I have also added "proxy": "http://localhost:8000", in frontend package.json file
Here is my form
function PostCreate() {
const [title, setTile] = useState("");
const [content, setContent] = useState("");
const [image, setImage] = useState({});
const dispatch = useDispatch();
const post = useSelector((state) => state.postReducer);
const fileOnChange = (e) => {
setImage(e.target.files[0]);
};
const submitPost = (e) => {
e.preventDefault();
const formData = new FormData();
formData.append("image", image);
dispatch(createPost(title, content, image));
};
return (
<div className="postCreate">
<h3 className="postCreate__heading">Create New Post</h3>
<div className="formBody">
<form onSubmit={submitPost}>
<div className="formInputs">
<label className="label">Title</label>
<input
className="titleInput"
type="text"
value={title}
onChange={(e) => setTile(e.target.value)}
placeholder="Enter the Title of the Post"
/>
</div>
<div className="formInputs">
<input type="file" onChange={fileOnChange} />
</div>
<div className="formInputs">
<label className="label">Content</label>
<textarea
className="titleInput"
type="text"
style={{
width: "1500px",
height: "500px",
color: "black",
outline: "none",
border: "none",
borderRadius: "6px",
}}
value={content}
onChange={(e) => setContent(e.target.value)}
/>
</div>
<div className="button">
<Button type="submit" variant="contained" color="primary">
Post
</Button>
</div>
{/* <button type="submit">Post</button> */}
</form>
Here is my action
export const createPost = (title, content, image) => async (dispatch) => {
try {
dispatch({ type: POST_POST_LOADING });
const config = { headers: { "Content-Type": "application/json" } };
const { data } = await axios.post(
"/api/newpost",
{ title, content },
config
);
dispatch({
type: POST_POST_SUCCESS,
payload: data,
});
} catch (error) {
dispatch({
type: POST_POST_FAIL,
payload: error,
});
}
};
Here is my postController
const createPost = async (req, res) => {
const { title, content, writer, comment, image } = req.body;
const fileType = req.file.mimetype.split("/")[1];
const newFileName = req.file.filename + "." + fileType;
fs.rename(
`uploads/images/${req.file.filename}`,
`uploads/images/${newFileName}`,
(req, res) => {
console.log("Renamed");
}
);
// const imageUrl = req.file.filename;
const newPost = await Post.create({
title,
content,
writer,
comment,
image,
// imageUrl,
});
if (newPost) {
res.send("Post created");
console.log("Post created");
} else {
res.status(201).send("Post not created");
console.log("Post not created");
}
};
Here is my routes
router.post("/newpost", upload.single("image"), createPost);
You're creating a form, which is a good start, but not sending it with axios.
To send a file from frontend to backend, you need to construct a form using FormData API and append the file to it. You can also append additional data to it.
Here is how I would change your code to work. In your form file:
const formData = new FormData();
formData.append('image', image);
formData.append('title', title);
formData.append('content', content);
dispatch(createPost(formData));
Then change your action to:
export const createPost = (formData) => async (dispatch) => {
try {
dispatch({ type: POST_POST_LOADING });
const config = { headers: { "Content-Type": "multipart/form-data" } };
const { data } = await axios.post(
"/api/newpost",
formData,
config
);
dispatch({
type: POST_POST_SUCCESS,
payload: data,
});
} catch (error) {
dispatch({
type: POST_POST_FAIL,
payload: error,
});
}
};

Cannot save image with multer and react

I'm trying to send some string and an image to my db from a form in React component. Everything is saved, also the image name, but the file is not in the pubblic/images folder. My req.file is alway undefined and my data always an empty object
This is the Multer middleware
//Multer
const path = require("path");
const multer = require("multer");
const store = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "public/images");
},
filename: function (req, file, cb) {
cb(null, Date.now() + path.extname(file.originalname));
},
});
//Upload parameters
const upload = multer({
storage: store,
});
this is the post request of node
router.post("/", upload.single("image"), verify, async (req, res, next) => {
console.log(req.file);
const book = new Book({
title: req.body.title,
author: req.body.author,
image: req.body.image,
});
try {
const savedBook = await book.save();
res.send(savedBook);
} catch (error) {
res.send(error);
}
});
React
const token = useSelector((state) => state.token.token);
const data = new FormData();
//set Cover on change
const onChange = (e) => {
console.log(e.target);
data.append("image", e.target.files[0]);
console.log(data);
};
//Post Register
const Submit = async (e) => {
e.preventDefault();
await axios
.post(
"http://localhost:3000/api/book",
{
title: titleInput,
author: authorInput,
image: data,
},
{
headers: {
"auth-token": token,
},
}
)
.then((res) => {
console.log(res);
console.log(data);
})
.catch((error) => {
// handle error
console.log(error);
});
setAuthor("");
setTitle("");
};
Form
<form encType="multipart/form-data">
<input
type="text"
id="title"
value={titleInput}
name="title"
placeholder="title"
onChange={(e) => {
setTitle(e.target.value);
}}
/>
<input
type="text"
id="author"
value={authorInput}
name="author"
placeholder="Author"
onChange={(e) => {
setAuthor(e.target.value);
}}
/>
<input type="file" name="image" onChange={onChange} />
<button type="submit" onClick={Submit}>
Submit
</button>
</form>
Solved by changing the component code and sending data (create with Format()) to the node app.
//Post Register
const Submit = async (e) => {
e.preventDefault();
console.log(filename.name);
const data = new FormData();
data.append("author", authorInput);
data.append("title", titleInput);
data.append("image", filename);
data.append(
"imageTitle",
titleInput.split(" ").join("").toLowerCase() + ".jpg"
);
await axios
.post("http://localhost:3000/api/book", data, {
headers: {
"auth-token": token,
},
})
.then((res) => {
console.log(res);
})
.catch((error) => {
// handle error
console.log(error);
});
setAuthor("");
setTitle("");
};

Resources