why state is not changing when changing the line of the setstate - reactjs

please need your help,
when changing the following line setloadingstate(prevState => prevState = false) to be inside the arrow function inside promise will work fine but when remaining as following, it doesn't work fine and state remains false, any explanation?
const IngredientsHandler=(ingredients)=>{
setloadingstate(prevState => prevState = true)
fetch('https://ingredients.firebaseio.com/ig.json',{
method:'POST',
body:JSON.stringify(ingredients),
headers:{
ContentType:'application/json'
}
}).then(response => {
return response.json()
},
)
.then(
responseData => {
setIngredientsState((prevState) => ([...prevState,{id:responseData.name,...ingredients}]))
},
setloadingstate(prevState => prevState = false)
)
}

Not sure why you're using prevState = true within setloadingstate when you aren't even using prevState value. Try this
const IngredientsHandler=(ingredients)=>{
setloadingstate(true);
fetch('https://ingredients.firebaseio.com/ig.json',{
method:'POST',
body:JSON.stringify(ingredients),
headers:{
ContentType:'application/json'
}
}).then(response => {
return response.json();
}).then(responseData => {
setIngredientsState((prevState) => ([...prevState,{id:responseData.name,...ingredients}]));
}).finally(() => {
setloadingstate(false);
});
}
async / await is cleaner
const IngredientsHandler= async (ingredients)=>{
setloadingstate(true);
try {
const response = await fetch('https://ingredients.firebaseio.com/ig.json',{
method:'POST',
body:JSON.stringify(ingredients),
headers:{ ContentType:'application/json'}
});
const responseData = await response.json();
setIngredientsState((prevState) => ([...prevState,{id:responseData.name,...ingredients}]));
} catch(ex) {
console.error({ ex }); // handle error(s)
} finally {
setloadingstate(false);
};
}

Related

useEffect: How to put data in the state in order

I'd like to ask how to retrieve data through use Effect.
The flow I want is as follows.
First, I want to get the 'cards' state, fill the cards with data, and then fill the data through the cardsPromises after that.
But my code couldn't get cards and wordAll, and the empty value came out.
I think it's because the cards are still empty, but I don't know how to operate in order.
Please tell me how to do it.
const [wordAll, setWordAll] = useState([]);
const [cards, setCards] = useState([]);
useEffect(() => {
axios
.get("http/api/words/", {
headers: {
Authorization: cookies.token,
},
})
.then((response) => {
setCards(response.data);
})
.catch((error) => {
console.log(error);
});
const cardsPromises = cards.map((contents) =>
axios.get(
`http/api/words/detail_list/?contents=${contents.contents}`,
{
headers: {
Authorization: cookies.token,
},
}
)
);
console.log("cards", cards);
Promise.all(cardsPromises)
.then((response) => {
console.log("resp", response.data);
setWordAll(response.data);
})
.catch((error) => {
console.log("err==>", error);
});
}, []);
You are correct, cards array is still empty in the useEffect callback when the fetching the data. I suggest converting to async/await and waiting for the first fetch to resolve and using that value of cards for the fetching of the rest of the data.
const [wordAll, setWordAll] = useState([]);
const [cards, setCards] = useState([]);
useEffect(() => {
const fetchData = async () => {
try {
const{ data: cards } = await axios.get(
"http/api/words/",
{
headers: {
Authorization: cookies.token,
},
},
);
setCards(cards);
const cardsPromises = cards.map((contents) =>
axios.get(
`http/api/words/detail_list/?contents=${contents.contents}`,
{
headers: {
Authorization: cookies.token,
},
}
);
);
const wordAllResponse = await Promise.all(cardsPromises);
const wordAll = wordAllResponse.map(({ data }) => data);
setWordAll(wordAll);
} catch (error) {
// handle any errors, rejected Promises, etc..
}
};
fetchData();
}, []);
Wrap your 2nd axios call inside a function, and call it after 1st axios call returns.
useEffect(() => {
const getWords = (cards) => {
const cardsPromises = cards.map((contents) =>
axios.get(
`http/api/words/detail_list/?contents=${contents.contents}`,
{
headers: {Authorization: cookies.token}
}
)
);
Promise.all(cardsPromises)
.then((response) => {
setWordAll(response.data);
})
.catch((error) => {
console.log("err==>", error);
});
})
axios
.get("http/api/words/", {
headers: { Authorization: cookies.token },
})
.then((response) => {
const cards = response.data;
setCards(cards);
getWords(cards);
})
.catch((error) => {
console.log(error);
});
}, [])
Now dependency chain is clearer.

async function in react component isn't working when triggered from the axios request

network.services.js
axiosCall = (axiosURL) => {
// const axiosURL = "https://api.github.com/user"
axios.get(axiosURL, {
headers: {
'Authorization': `qwdvryjutmnevw`,
}
}).then((res) => {
console.log(res.data);
return res.data;
}).catch((error) => {
throw error.message;
// console.error(error);
// toast.error(error.message);
})
}
component.js
const getData = async () => {
const asyncExample = async () => {
const result = await networkServices.axiosCall("/api/v1/calendars");
const responseData = await result;
console.log(responseData);
return responseData;
}
const data = asyncExample()
data.then(function(result) {
console.log(result); // "Some User token"
})
}
Trying to get data from service to my component in const result, console form service is consoling data but component is always returning undefined instead of data from the service file. SetTimeout function is also not working in component.
You have many mistakes. I advise you to take a look at documentation about Promises
First one:
You don't return data in axiosCall
A way to return data:
axiosCall = (axiosURL) => new Promise((resolve, reject) => {
axios.get(axiosURL, {
headers: {
'Authorization': `yourTokenHere`,
}
}).then((res) => {
// return a response data
resolve(res.data);
}).catch((error) => {
// return only error message
reject(error.message);
})
})
to use axiosCall:
try {
// don't forgot to configure axios with base url
const data = await axiosCall('/api/v1/calendars');
// do something with your data
} catch (e) {
// do something with error message
console.log(e);
}
Second:
Your make mistakes when call async function
Look at this example:
const getData = () => {
networkServices
.axiosCall("/api/v1/calendars")
.then(function(result) {
// when promise resolve
console.log(result);
})
.catch(error => {
// when promise reject
console.log(error)
})
}

call function synchronously in reactjs

I want to call function only after previous function gets executed. I tried with promises but its not working,I also tried with async await but the last function is getting executed.After execution of first function its state value i want to pass to next function and so on.Please help me in this.Thanks in advance.
handleAllFunctionsOnClickPayLater() {
let promise = Promise.resolve();
promise
.then(() => this.handleGuestLogin())
.then(() => setTimeout(this.handleAddress(),1000))
.then(() => setTimeout(this.handlePayLater(),2000))
}
handleGuestLogin() {
const UserDetails = {
name: this.state.name,
email: this.state.email,
mobile: this.state.number
}
fetch(api,{
method : 'POST',
body: JSON.stringify(UserDetails)
})
.then(res => res.json())
.then(data => {
return this.setState({
cid: data.Data.cid
},() => {console.log(this.state.cid)})
})
}
handleAddress() {
var address_details = {
cid:this.state.cid
...other details
}
fetch(api,{
method : 'POST',
body: JSON.stringify(address_details)
})
.then(res => res.json())
.then(data => {
console.log("address added in db customer_address",data);
return this.setState({
address_id: data.address_id,
})
}
handlePayLater = () => {
var bookingDetails = {
cid: this.state.cid,
address_id: this.state.address_id
}
fetch(api,{
method : 'POST',
body : JSON.stringify(bookingDetails)
})
.then(res => res.json())
.then(data => {
return this.setState({bookingId:data.booking_id});
}
Assuming handleAddress, handleGuestLogin and handlePayLater return promises, you can use an async/await function
synchronousPromises = async () => {
try {
const handleGuestLoginResult = await this.handleGuestLogin();
const handleAddressResult = await this.handleAddress();
const handlePayLaterResult = await this.handlePayLater();
} catch (error)
{
return reject(error); //will cause .catch to fire
}
return resolve([
handleGuestLoginResult,
handleAddressResult,
handlePayLaterResult
]); //will cause .then to fire
}
since synchronousPromises is an async function, it itself returns a promise. to use it, you can call it as
callSyncronousPromises = () => {
synchronousPromises()
.then(success => {
//handle success
})
.catch(error => {
//handle error
}
}

componentDidMount not sending data after setting state

I am decoding a token to get the current users email address and setting to facultyEmail state and sending that to the backend to get a response. But facultyEmail is empty because componentDidMount is asynchronous ,it works outside the componentDidMount() but I don't know any way to handle the axios get request with params outside the componentDidMount i dont have event to invoke it.Thanks for the help
componentDidMount() {
const token = localStorage.usertoken;
const decoded = jwt_decode(token);
this.setState({
facultyEmail: decoded.email
});
axios
.get("faculty/Course", {
params: {
facultyEmail: this.state.facultyEmail
}
})
.then(res => {
this.setState({
class: res.data
});
})
.catch(err => {
console.log(err);
});
console.log("courses", this.state.facultyEmail);
}
The setState is asynchronous. You have to use setState callback or async/await
using callback
componentDidMount() {
const token = localStorage.usertoken;
const decoded = jwt_decode(token);
this.setState({
facultyEmail: decoded.email
}, () => {
axios
.get("faculty/Course", {
params: {
facultyEmail: this.state.facultyEmail
}
})
.then(res => {
this.setState({
class: res.data
});
})
.catch(err => {
console.log(err);
});
console.log("courses", this.state.facultyEmail);
});
}
using async/await
async componentDidMount() {
try {
const token = localStorage.usertoken;
const decoded = jwt_decode(token);
await this.setState({
facultyEmail: decoded.email
});
const res = await axios.get("faculty/Course", {
params: {
facultyEmail: this.state.facultyEmail
}
})
this.setState({
class: res.data
});
console.log("courses", this.state.facultyEmail);
} catch (err) {
console.log(err);
}
}
You are using same email you are using in setState to make the API call, there is no need for two setStates. That would cause us anomalies and is not a recommended practice. You can do this in two ways:
Way 1:
componentDidMount() {
const token = localStorage.usertoken;
const decoded = jwt_decode(token);
axios.get("faculty/Course", {
params: {
facultyEmail: decoded.email
}
}).then(res => {
this.setState({
class: res.data,
facultyEmail: decoded.email
});
}).catch(err => {
console.log(err);
});
}
render() {
console.log(this.state.class, this.state.facultyEmail);
// This will have the values from setstate triggered inside axios.
return(
<div> Sample </div>
)
}
Alternate approach:
loadDataFromApi(email) {
axios.get("faculty/Course", {
params: {
facultyEmail: email
}
}).then(res => {
this.setState({
class: res.data
});
}).catch(err => {
console.log(err);
});
}
componentDidMount() {
const token = localStorage.usertoken;
const decoded = jwt_decode(token);
this.setStats({
facultyEmail: decoded.email
}, () => {
// The callback function would reflect the updated email.
this.loadDataFromApi(this.state.facultyEmail);
});
}
Why not just store facultyEmail in memory until the 2nd setState, avoiding the first one? The axios call is async, so you'll need to put the console.log in the render function (and you should only log it once it's actually in state).
componentDidMount() {
const token = localStorage.usertoken;
const decoded = jwt_decode(token);
const facultyEmail = decoded.email;
axios
.get("faculty/Course", { params: { facultyEmail } })
.then(res => { this.setState({ class: res.data, facultyEmail }); })
.catch(err => { console.log(err); });
}
render() {
if (this.state.facultyEmail) console.log("courses", this.state.facultyEmail);
return ();
}

problem with fetch in componentDidMount()

my list of users is undefined when i try to console.log it.
Maybe i didn't get something ?
I'd like to get my list of users from my api who works (tested with postman) and put it into the console next i'd like to map my users to show it on the app
class Test extends Component {
constructor(props) {
super(props);
this.state = {
users: [],
}
}
componentDidMount() {
console.log("component did mount");
fetch("/user/list")
.then(res => {
return res.json();
})
.then(users =>
this.setState({users}, () =>
console.log("list of users => " + users)));
}
render() {
return (
<div className="form">
<ul>
{this.state.users.map((user) =>
<li key="user._id">{ user.name }</li>
)}
</ul>
</div>
);
}
} export default Test;
Thanks for help !
You are calling res.json() rather than returning res.json() from the first then on your fetch call
I've found this pattern to be helpful:
fetch(url)
.then(res => res.ok ? res.json() : Promise.reject())
As your code is now, users (the parameter in the second then would be undefined, because you are not returning anything from the first then
you have to return the res.json() to use it in the next .then()
.then(res => {
res.json();
})
should be
.then(res =>
res.json();
)
Or
.then(res => {
return res.json();
})
https://javascript.info/promise-chaining
You should be passing your res into res.json() and returning the results into your state.
componentDidMount() {
console.log("component did mount");
fetch("/user/list")
.then(res => res.json())
.then(users =>
this.setState(users,
() => {
console.log("list of users => " + users)
})
);
}
Michael Jasper response help me so much!
I found that fetch with GET method does not work if we pass any request body.
the full example is here
https://github.com/alexunjm/todo-list-react
const buildRequestOptions = ({
method = "GET",
raw = null, // I had my error here!, with GET raw need to be null
customHeaders = {name: 'value'},
}) => {
var myHeaders = buildHeaders(customHeaders);
var requestOptions = {
method,
headers: myHeaders,
body: raw,
redirect: "follow",
};
return requestOptions;
};
const listTasks = () => {
const url = `${uriBase}/task/sample`;
const requestOptions = buildRequestOptions({
customHeaders: { "Content-Type": "application/json" },
});
return fetch(url, requestOptions);
}
const asyncFn = ({
promiseToWait,
pendingFn,
successFn,
errorFn,
}) => {
return (dispatch) => {
dispatch(pendingFn());
promiseToWait
.then((res) => {
if (res.ok) {
return res.json();
}
// handled from server status 422 and 401
if (res.status === 422) {
// error message on body from server
return res.json();
}
if (res.status === 401) {
// custom error message hardcoded
return {errors: {action: 'no authorized'}}
}
console.log("http response no controlled", res);
return Promise.reject();
})
.then((body) => {
if (body.errors) {
const errors = Object.keys(body.errors).map(
(key) => key + " " + body.errors[key]
);
dispatch(errorFn(errors.join("; ")));
} else {
dispatch(successFn(body));
}
return body;
})
.catch((error) => {
console.log("error", error);
dispatch(errorFn("Unavailable server connection"));
});
};
};
const queryTasks = () => {
return asyncFn({
promiseToWait: listTasks(),
pendingFn: apiPending,
successFn: apiSuccessList,
errorFn: apiError,
});
}

Resources