Axios - catch() possibility to pass props? - reactjs

I am trying to setState for loading after a response error has been catched by the axios .catch() function, but so far, it only allows the error props itself. Is there a way to pass the state props so I can setState after an error has been catched?
this.setState({loading: true})
axios.get(`${wordpressUrl}/wp-json/wp/v2/pages/727?password=${password}`)
.then(res => {
this.setState({
data: res.data,
loading: false,
visible: true
})
})
.catch((error) => {
if (error.response) {
alert("Invalid password.");
this.setState({ loading: false });
this.forceUpdate();
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
}
});
Code example is what I would ideally want to achieve.
EDIT: 1
I tried the following, but the .then function just skips the response.status else and continues to catch() the error:
.then(response => {
if(response.status === 403) {
alert("Invalid password.");
this.setState({ loading: false });
this.forceUpdate();
} else {
this.setState({
data: response.data,
loading: false,
visible: true
})
}
})
.catch(error => {
if (error.response) {
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
}
});
I AM NOT GONNA SET THIS AS AN ANSWER, SO I'LL EDIT MY QUESTION:
It wasn't clear enough for me how to pass any props to the catch to so on make a detailed and user friendly catching method.
So I did the following:
.catch(error => {
this.setState({loading: false})
console.clear()
console.log(error);
})

If you want to send a variable to the catch block you can use throw inside of one of the then block. You can use throw like a return statement.
throw myProps.
You will then get myProps as the argument you declared for the catch block.

Related

How to handle bad request in fetch()

I know this is a basic and often recurring issue, but I am still unable to make it work.
I have the following code
handleAdd = (event: any): void => {
// ...
// create new task
try {
// send data to backend
fetch(`/api/tasks?name=${name}&priority=${priority}`, { method: 'post' })
.then(response => { if (!response.ok) {
throw new Error('error => how to get bad request message here?') } })
}
// handle exception
catch (e) {
console.log(e);
this.setState({
isError: true,
errorMessage: e.message
});
}
}
the API returns 400 with some error message
but in the browser I get
So I have two questions
Why the throw new Error() in fetch does not goes to catch(e) {} method (if the error is outside fetch function, it works well)? How to rewrite this line to get into catch method? I think it has something to do with the Promise object?
How to get the bad request message from response object?
update, working solution
fetch(`/api/tasks?name=${name}&priority=${priority}`, { method: 'post' })
.then(response => {
if (!response.ok) {
response.text().then(function (text) {
throw Error(text);
}).catch((e) => {
this.setError(e.message);
});
}
})
how to get response.text() into the Error exception?
when using promises, you can choose between chaining your promise with then/catch or using async/await.
if you are chaining promise you should chain with a catch:
handleAdd = (event: any): void => {
// send data to backend
fetch(`/api/tasks?name=${name}&priority=${priority}`, { method: 'post' })
.then(response => { if (!response.ok) {
throw new Error('error => how to get bad request message here?') } }
).catch((e) => {
console.log(e);
this.setState({
isError: true,
errorMessage: e.message
})
});
}
if you prefer you can change your function to async/await. with that you would use a try/catch block:
// mark your function as async
handleAdd = async (event: any): void => {
try {
// await your fetch response
const response = await fetch(`/api/tasks?name=${name}&priority=${priority}`, { method: 'post' })
if (!response.ok) {
throw new Error('error => how to get bad request message here?')
}
}
// handle exception
catch (e) {
console.log(e);
this.setState({
isError: true,
errorMessage: e.message
});
}
}
I'd imagine if you are not using React, it could be that you have a local or global error or warning message area, so that the
fetch
.then()
.catch(err => {
// display "try again later" here
});
But since you are using React and probably Redux, you could dispatch an action NETWORK_ERROR instead so that the reducer will create that error message "try again later":
fetch
.then()
.catch(err => {
// dispatch the action for NETWORK_ERROR here
});
try it this way and you are good to go
fetch(`/api/tasks?name=${name}&priority=${priority}`, { method: 'post' })
.then(response => { if (!response.ok) {
throw new Error('error => how to get bad request message here?') }
}).catch(error => {
// handle the error here
console.log(e);
});

this.props.history.push('/') is getting executed even if there is an error

Even if there is an error in fetching data from firebase my router navigates to root component
axios.post('/orders.json', order)
.then(response => {
this.setState({ loading: false });
this.props.history.push('/');
})
.catch(err => {
//console.log(err)
this.setState({ loading: false });
});

Infinite loop on react ComponentDidUpdate

I have a model called Event, after updating the Event, when I try to update the change to the view with componentDidUpdate it keeps looping forever (infinite loop). I have searched and saw people that had the same problem but I can't seem to get it working.
here is my componentDidUpdate inside EventComments component
componentDidUpdate() {
axios
.get(
"http://localhost:9000/events/" +
this.props.match.params.id +
"/eventcomments"
)
.then((response) => {
this.setState({ event: response.data });
this.setState({ eventcomments: response.data.eventcomments });
})
.catch(function (error) {
console.log(error);
});
}
Please what should I do to get this infinite loop to stop?
You need to wrap your event in a conditional. Reference from the docs:
componentDidUpdate(prevProps) {
// Typical usage (don't forget to compare props):
if (this.props.userID !== prevProps.userID) {
this.fetchData(this.props.userID);
}
}
Your example:
componentDidUpdate(prevProps) {
if(prevProps.id !== this.props.match.params.id){
axios
.get(
"http://localhost:9000/events/" +
this.props.match.params.id +
"/eventcomments"
)
.then((response) => {
this.setState({ event: response.data });
this.setState({ eventcomments: response.data.eventcomments });
})
.catch(function (error) {
console.log(error);
});
}
}
after so many tries, I have managed to make it work. but, if you know a better way of doing it than this, please let me know.
Here is my what I did
componentDidUpdate(prevProps, prevState) {
if (prevState.event === this.state.event) {
axios
.get(
"http://localhost:9000/events/" +
this.props.match.params.id +
"/eventcomments"
)
.then((response) => {
this.setState({ event: response.data });
})
.catch(function (error) {
console.log(error);
});
}
}

Updating object in react under componentDidMount

I able to get the right data from my API node.js server. however when i try to setstate the object to render it it keeps returning null
i tried to use spread operator before the response but it still not working
import React, { Component } from "react";
import axios from "axios";
class Profile extends Component {
constructor(props) {
super(props);
this.state = {
UserData: null,
isLoading: false,
error: null
};
}
componentDidMount() {
this.setState({ isLoading: true });
axios
.get(
`http://localhost:5000/api/v1/profile/${this.props.match.params.platform}/${this.props.match.params.gamertag}`
)
.then(response => {
console.log(response.data);
})
.then(response => {
this.setState({
UserData: response.data,
isLoading: false
});
})
.catch(error => this.setState({ error, isLoading: false }));
}
render() {
const { isLoading, UserData } = this.state;
if (isLoading) {
return <p>Loading ...</p>;
}
console.log(UserData);
return <div>{UserData}</div>;
}
}
export default Profile;
when i try to log. the UserData log "null", but the "console.log(response.data)" works fine so it have to do something with the setState
when you chain data method like .then(), the following chained methods automatically receive value returned by the previous function.
getData
.then(res => console.log(res))
console.log itself will return nothing, thus the following .then() method will receive nothing.
getData
.then(res => console.log(res))
.then(data => console.log(data))
So if you do this, the second console.log() will log null.
You can fix it by returning something in your console.log step:
getData
.then(data => {
console.log(data);
return data;
})
.then(data => this.setState({ data: data }));
And the second console.log() will log properly.
You don't need two chain two then()'s, you can get the response and set the state after .then()
componentDidMount() {
this.setState({ isLoading: true });
axios
.get(
`http://localhost:5000/api/v1/profile/${this.props.match.params.platform}/${this.props.match.params.gamertag}`
)
.then(response => {
this.setState({
UserData: response.data,
isLoading: false
});
})
.catch(error => this.setState({ error, isLoading: false }));
}

TypeError: Cannot read property 'setState' of undefined/XML

I am calling service that is using XML, so i want to parse XML to JSON and the JSON data set as my react state but i am getting.
TypeError: Cannot read property 'setState' of undefined
axios
.get(session_url)
.then(function(response) {
parseString(response.data, (err, result) => {
if (err) {
throw err;
} else {
this.setState({
odm: result.data,
loading: false,
});
}
});
})
.catch(function(error) {
console.log(error);
});
You're mixing and matching function()s that don't capture this and arrow (=>) functions which do.
Simply use arrow functions everywhere and the this (that's your React component) will be properly captured:
axios
.get(session_url)
.then(response => {
parseString(response.data, (err, result) => {
if (err) {
throw err;
} else {
this.setState({
odm: result.data,
loading: false,
});
}
});
})
.catch(error => {
console.log(error);
});
Better yet, if you can, use an async function:
// promisified version of `parseString`:
const parseStringP = data =>
new Promise((resolve, reject) =>
parseString(response.data, (err, result) => {
if (err) return reject(err);
resolve(result);
}),
);
// ...
try {
const response = await axios.get(session_url);
const result = await parseStringP(response.data);
this.setState({
odm: result.data,
loading: false,
});
} catch (error) {
console.log(error);
}

Resources