After post request a post not appearing immediately - node.js

I have a Node backend with React frontend. When a user creates a movie review, the post request gets handled with axios. Right after that, the user gets taken to a homepage but the review is not there yet. When I refresh the page, the review appears.
How can I fix this issue so that the user doesn't have to get confused when, after submitting, they don't see the review in homepage? Should I refetch every time a user hits the homepage? Or is React doing it behind the scenes but early so the review isn't registered?
My redux request code:
the reducer
export const postNewReview = review => (dispatch, getState) => {
return apiCall("post", `http://localhost:8000/review`, review)
.then(res => {})
.catch(err => addError(err.message));
};
the api call function
export function apiCall(method, path, data){
return new Promise((resolve,reject) => {
return axios[method.toLowerCase()](path,data)
.then(res => {
return resolve(res.data);
})
.catch(err => {
return reject(err.response.data.error);
});
});
}
handling submitting
handleSubmit = (e) => {
e.preventDefault();
this.props.postNewReview(this.state);
this.setState({user: '', title: '', image: '', text: ''});
this.props.history.push('/');
}

Related

How to make 2 POST request from a react form

I have made a react form and want to make a post request to webhook.site with the form data. If I receive a 200 status code then I want to send the form data to a backend express server for further operation.
I am using axios to make the POST request.
This is the axios snippet from my react form:
import React, { Fragment, useState } from "react";
import axios from "axios";
const Form = () => {
const [candidate, setCandidate] = useState({
fullName: "",
phoneNumber: 0,
email: "",
gitProfile: "",
linkToResume: "",
designation: "",
interest: "",
});
const onChange = e =>
setCandidate({ ...candidate, [e.target.name]: e.target.value });
const onSubmit = e => {
e.preventDefault();
axios
.post("http://localhost:5000/", {
candidate,
})
.then(res => {
console.log(res, candidate);
});
};
Currently i am directly sending data to the backend. I have individually checked posting to both the webhook.site and backend, the code is working fine. But I want to do it simultaneously. If I get a 200 status code after posting to webhook.site, then only I want to send the form data to backend.
axios
.post("http://localhost:5000/", {
candidate,
})
.then(res => {
console.log(res, candidate);
// Write your another post request here because if your first request return 200 statusCode it will execute this function otherwise it will go catch function
}).catch(error => {
// if your first request failed then it execute this function. Here you can get error message.
console.log(error);
});
Check if first POST return status 200, then call next request.
axios
.post("http://localhost:5000/", {
candidate,
})
.then(res => {
console.log(res, candidate);
if (res.status === 200) {
axios.post('/url', {data})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
}).catch(function (error) {
console.log(error);
});

How to send React to Express server get Request passing id

Hello I am learning on MERN Stack dev, so I am trying to implement a get request where by I send in and ID and then try searching through the collection by the id the return the entry back to the client so I have been trying to implement this but I do not know where I am going wrong because I get a 404 response
Code below is the client side where I try to send through the get request
const ProductDetails = (props) => {
const product_id = window.location.href.split("/")[4];
console.log(product_id);
const getProduct = () => {
const url = `http://127.0.0.1:5000/single-women-clothes/id?=${product_id}`;
Axios.get(url)
.then((response) => {
console.log(response.data);
})
.catch((error) => {
console.log(error);
});
};
getProduct();
return (
<div>
<h1>Details</h1>
</div>
);
};
router.get("/single-womens-clothes/:id", (request, response) => {
console.log(request.params);
MongoClient.connect(
mongoURI,
{ useNewUrlParser: true, useUnifiedTopology: true },
(error, client) => {
client
.db("OnlineStore")
.collection("WomensClothes")
.find(request.params.id)
.toArray()
.then((data) => {
response.status(200).json(data);
})
.then((response) => {
console.log("Single Female Product Fetch Successful");
})
.catch((error) => {
console.log(error);
});
}
);
});
Can I please get help on how I can pass the ID to the server then search through collection through this given ID
Anytime you have a 404 error, the issue is usually coming from putting the wrong url.
In your front-end:
single-women-clothes/id?=${product_id}
Backend
/single-womens-clothes/:id
You are missing an "s" in the front-end url in "womens"
To answer your second question:
You shouldn't do id?= just simply leave it as
single-women-clothes/${product_id}

POST request with Axios not sending data to my server

Here is my React code for the form submission:
const handleSubmit = (e) => {
e.preventDefault();
console.log('item:', item);
Axios.post('http://<MY_SERVER>/item/add', {name:item})
.then(response => console.log(response))
.catch(err => console.log(err));
};
and this is the code in my Node API:
// Add a new Item
app.post('/item/add', (req, res) => {
const newItem = new Item({
name: req.body.name
});
newItem.save()
.then(item => {
res.json({msg: 'success'});
})
.catch(err => console.log(err));
});
When I run the handleSubmit nothing happens. I only get the console.logs... Also, here is the error from my server
'ValidationError: item validation failed: name: Path' `name` is required
So it is clear that the data sent over to the api is never received. I've tried changing it up in many ways I have came across online but no luck.
I have attached both ways to post data i.e. Form URL Encoded and JSON. For sending Form Url Encoded data we need an additional Library querystring.
You can install it using npm install query-string
Here is the code for both the requests. You don't need query-string if you are using content type application/json.
Here you go
var axios = require('axios');
const qs = require('querystring');
function sendFormUrlEncodedData() {
const headers = {
'Content-Type': 'application/x-www-form-urlencoded'
};
const payload = {
name: 'morpheus',
job: 'leader'
};
//Send data with form url using querystring node package for it.
axios
.post('https://reqres.in/api/users', qs.stringify(payload), {
headers: headers
})
.then(res => {
console.log(res.data);
})
.catch(err => {
console.log(err);
});
}
function sendJSONData() {
const headers = {
'Content-Type': 'application/json'
};
const payload = {
name: 'morpheus',
job: 'leader'
};
//Send data with JSON, so stringifying it.
axios
.post('https://reqres.in/api/users', JSON.stringify(payload), {
headers: headers
})
.then(res => {
console.log(res.data);
})
.catch(err => {
console.log(err);
});
}
sendFormUrlEncodedData();
sendJSONData();
First of all check whether your backend code is working or not by using postman. I think you are getting validation error because of the error of your backend code. And also check whether that you are implemented the name attribute correctly with its data type.
After that update, the react code as below.
import axios from 'axios';
constructor() {
this.item = {
name: ''
}
}
handleSubmit(event) {
console.log('item:', this.item.name);
event.preventDefault();
axios.post('http://<MY_SERVER>/item/add', this.item)
.then(response => {
console.log(response.data);
})
.catch(error => {
console.log(error);
});
}

Axios does not return the error in the frontend?

I create a server on NodeJs by using Express and MongoDB (Mongoose) to create REST API after that I connect that API to my Frontend (ReactJS). the problem is that when I send post request from Axios, but on error (Duplicate Key) they not respond to catch and give a response on .then like that {data: "You Cannot Add Duplicate Link", status: 200, statusText: "OK", headers: Object, config: Object…}
FrontEnd:
axios
.post(`${SERVER}`, post) // Here Post is an object
.then(async res => {
await this.setState({ host: res.data._id });
})
.then(() => this.setState({ loading: false }))
.catch(async error => {
await this.setState({ error: error.res });
});
}
BackEnd:
const post_link_with_id = async (req, res) => {
await models
.create({
// Objects like obj_key: req.body.obj_model
})
.then(result => res.send(result))
.catch(err =>
err.code === 11000 ? res.send("You Cannot Add Duplicate Link") : ""
);
};
Make sure you are sending error status while send the response from the server.
The standard way to send a response is by using a status code.
Like,
res.status(statusCode).send(responseMessage);
For error in server, you should use the following response,
err.code === 11000 ? res.status(404).send("You Cannot Add Duplicate Link") : "";
Your final backend code should,
const post_link_with_id = async (req, res) => {
await models
.create({
// Objects like obj_key: req.body.obj_model
})
.then(result => res.send(result))
.catch(err =>
err.code === 11000 ? res.status(400).send("You Cannot Add Duplicate Link") : ""
);
};
You may want to change the suitable status code.
For details, check the documentation.
Also fix your front end setState() method, as suggested in the comments.

ReactJS - redirect on the login page if session expired

I have followed some tutorial to build an authentication in React, Node and Redux. The basic functionality works, however, when I keep the application open and then get back to it (when the session expired), I get this error message:
Unhandled Rejection (TypeError): Cannot read property 'uploadURL' of undefined
Then I refresh the page and I get this error message:
TypeError: Cannot read property 'push' of undefined
Then, I refresh the page again and I am finally redirected on the homepage. The first 2 errors are a problem I am not sure how to get rid off them.
This is what my code looks like:
...
class Event extends Component {
constructor() {
super();
...
}
UNSAFE_componentWillMount() {
// I thought this if-block will redirect the user if the session is expired
if(!this.props.auth.isAuthenticated) {
console.log('unauthorized');
this.props.history.push('/');
}
this.uppy2 = new Uppy({ id: 'uppy2', autoProceed: true, debug: true })
.use(Tus, { endpoint: 'https://master.tus.io/files/' })
.on('complete', (result) => {
console.log(`Upload complete! We’ve uploaded these files: ${result.successful[0].uploadURL}`);
});
}
...
}
Event.propTypes = {
registerUser: PropTypes.func.isRequired,
auth: PropTypes.object.isRequired,
errors: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
auth: state.auth,
errors: state.errors
});
export default connect(mapStateToProps,{ registerUser })(withRouter(Event))
Here's the Redux code (I am beginner with the MERN stack):
import axios from 'axios';
import { GET_ERRORS, SET_CURRENT_USER } from './types'; // we list here the actions we'll use
import setAuthToken from '../../setAuthToken';
import jwt_decode from 'jwt-decode';
export const registerUser = (user, history) => dispatch => {
axios.post('/api/users/register', user)
.then(res => history.push('/login'))
.catch(err => {
dispatch({
type: GET_ERRORS,
payload: err.response.data
});
});
}
export const loginUser = (user) => dispatch => {
axios.post('/api/users/login', user)
.then(res => {
//console.log(res.data);
const { token } = res.data;
localStorage.setItem('jwtToken', token);
setAuthToken(token);
const decoded = jwt_decode(token);
dispatch(setCurrentUser(decoded));
})
.catch(err => {
dispatch({
type: GET_ERRORS,
payload: err.response.data
});
});
}
export const setCurrentUser = decoded => {
return {
type: SET_CURRENT_USER,
payload: decoded
}
}
export const logoutUser = (history) => dispatch => {
localStorage.removeItem('jwtToken');
setAuthToken(false);
dispatch(setCurrentUser({}));
history.push('/login');
}
How do I prevent the errors happening when the session is expired?
Thank you in advance!
ComponentWillMount won't be called if the page is loaded before the session expires. I suspect the first error is caused by some missing data because the request with the expired token failed. You would need to make sure the 401 or 403 error is handled and clear out the Redux state so the login page is shown when that happens.
I am not sure with this part !this.props.auth.isAuthenticated. Did you use mapDispatchToProps and connect for redux? You need to do this in your Event class to reach your reducer.
Also the thing that you can do is, before rendering your jsx code, declare a variable like let redirect = null and if !this.props.auth.isAuthenticated is correct, set this redirect variable to redirect = <Redirect to="/" /> (If you use browser routing!) and use this variable like this,
render() {
return (
{redirect}
)
}

Resources