Data cannot be assigned to state in interval function in useEffect - reactjs

Im getting data from axios async function and trying to assign to state in same function. When I print the values on console, i see that temporary value is not null but state is always null. when i rerender the page, state is not being null.
const [Pickup, setPickUp] = useState([]);
async function GetOrders() {
const result = await axios(
`EXAMPLEURL`,
);
setOrders(result.data);
var temp = [];
result.data.allOrders.forEach(element => {
if (element.order_type === 'PickupOrders') {
temp.push(element);
}
});
console.log(temp);
if (Pickup !== temp) {
setPickUp(temp);
}
}
useEffect(() => {
GetOrders();
const interval = setInterval(() => {
GetOrders();
console.log(Pickup);
}, 1000 * 5);
return () => clearInterval(interval)
}, []);
On console:
How can i fix this problem?

I assume you want to make a get request. Your axios function need to be completed such as ;
await axios
.get("YOUR URL", {
headers: // if you need to add header,
})
.then((response) =>{
setOrders(reponse.data);
})
.catch((error) => {
result = { errorMessage: error.message };
console.error('There was an error!', error);
});
return result;

Not completely sure what you're trying to achieve, but you can't compare Pickup !== temp this will be false all the time, you're comparing object references. Js will return all the time those values aren't equal.
This function GetOrders return a promise you don't need to use interval, you can use GetOrders.then(lambdaFunctionHere -> ());

Related

React how to wait for all axios to finish

I want to wait until all axios in useEffect are finished.
UseEffect:
useEffect(() => {
async function getHomePageContent() {
await HomePageServices.getSliderContent().then((response) => {
setSliderProduct(response.data);
});
await HomePageServices.getRecommendedProducts().then((response) => {
setRecommendedProducts(response.data);
});
await HomePageServices.getMostOrderProducts().then((response) => {
setMostOrderProducts(response.data);
});
await HomePageServices.getMostRatedProducts().then((response) => {
setMostRatedProducts(response.data);
});
}
getHomePageContent().catch((error) => {
console.log(error)
});
}, []);
Class:
class HomePageServices{
async getSliderContent(){
return await axios.get(baseURL+"/slider")
}
async getMostRatedProducts(){
return await axios.get(baseURL+"/mostRatedProducts")
}
async getMostOrderProducts(){
return await axios.get(baseURL+"/mostOrderProduct")
}
async getRecommendedProducts(){
return await axios.get(baseURL+"/recommendedProduct")
}
}
Can someone explain to me how to wait for all axios to end, and if one failed, how to find out which one it was?
Try using Promise.allSettled() which takes an iterable (e.g. array) of promises and resolves into array of results of each of them.
Results are represented as objects with status key, which can be rejected or fulfilled. The second key of the object is either value containing the resolved value, or reason in case promise was rejected.
Taking this, then your code in useEffect might be something like this:
useEffect(() => {
const getHomePageContent = async () => ({
const promises = [
HomePageServices.getSliderContent(),
HomePageServices.getRecommendedProducts(),
HomePageServices.getMostOrderProducts(),
HomePageServices.getMostRatedProducts()
];
const data = await Promise.allSettled(promises);
const [slider, recommended, mostordered, mostrated] = data;
// result for each of promise
console.log(slider); // { status: 'fulfilled', value: 123 }
console.log(recommended) // { status: 'rejected', reason: 'blah'}
});
getHomePageContent().catch((er) => console.log(er))
}, [])

Return the fetch response from another file

I am trying to call a function that calls fetch to an API from a React component in a separate file and am not finding the correct solution to get the correct response back.
When I debug, the result returns before the updateAccount function has completed and the final result is never returned to my update function.
Inside the fetch, the API returns the correct response whether it is successful or has validation errors and those results are correctly assigned to result.success and result.errors but the result doesn't get returned from the function so that the caller can make use of those values.
Inside of my React component:
import { updateAccount } from '../services/requests';
...
const update = (account: EditAccountModel) => {
const result = updateAccount(account);
if(result.errors.length > 0) {
// will notify of errors
console.log(result.errors); // is an empty array instead of validation errors
} else {
// will notify of success
console.log(result.success); // is an empty string instead of success message
}
}
...
My request file
export const updateAccount = (account: EditAccountModel | undefined): EditAccountResponseModel => {
const result = new EditAccountResponseModel();
fetch(baseUrl, {
method: 'PUT',
body: JSON.stringify(account),
headers
})
.then(response => {
if (!response.ok) {
return Promise.reject(response);
}
result.success = `${account?.name} was updated successfully!`
})
.catch(error => {
if (typeof error.json === "function") {
error.json().then(jsonError => {
result.errors.push(jsonError);
}).catch(genericError => {
result.errors.push(genericError);
});
}
});
return result;
}
The result reassignment happens inside then catch but it won’t be affective in the way you expected. The guaranteed way to return correct result is via a callback() passed to your updateAccount() if you could afford it:
export const updateAccount = (
account: EditAccountModel | undefined,
callback: Function
): EditAccountResponseModel => {
const result = new EditAccountResponseModel();
fetch(baseUrl, {
method: 'PUT',
body: JSON.stringify(account),
headers
})
.then(response => {
if (!response.ok) {
return Promise.reject(response);
}
result.success = `${account?.name} was updated successfully!`
callback(result);
})
.catch(error => {
if (typeof error.json === "function") {
error.json().then(jsonError => {
result.errors.push(jsonError);
callback(result);
}).catch(genericError => {
result.errors.push(genericError);
callback(result);
});
}
});
}
And inside your React component:
const update = (account: EditAccountModel) => {
const handleResult = (res) => {
// your result callback code
// ...
};
updateAccount(account, handleResult);
// ...
}
Alternative way that keeps your current structure is to change your current updateAccount() to an async function, then return await fetch().
You need to wait for the response . I'll let read more about how Promise work in JavaScript.
I wouldn't code updateAccount the same way you did, especially where you use the variable result and update it inside the flow of the promise (you really don't need that). You're also using React so you can use the state to store and update the result of the update function. But let's fix your problem first:
export const updateAccount = async (account: EditAccountModel | undefined): EditAccountResponseModel => {
const result = new EditAccountResponseModel();
await fetch(baseUrl, {
method: 'PUT',
body: JSON.stringify(account),
headers
})
.then(response => {
if (!response.ok) {
return Promise.reject(response);
}
result.success = `${account?.name} was updated successfully!`
})
.catch(error => {
if (typeof error.json === "function") {
error.json().then(jsonError => {
result.errors.push(jsonError);
}).catch(genericError => {
result.errors.push(genericError);
});
}
});
return result;
}
First make your function updateAccount async then await the result of the promise.
Now the same thing for the function update:
const update = async (account: EditAccountModel) => {
const result = await updateAccount(account);
if(result.errors.length > 0) {
// will notify of errors
} else {
// will notify of success
}
}

Why Promise.all is not getting values?

I am using React and inside useEffect I am pulling data but I am getting an emtpy array after all the promises are resolved and cannot figure out why.
Here is the code:
const data = mainnet.FairLaunch.pools.map((pool) => {
const loadingStakingData = async () => {
const stakedValue = await getStakeValue(pool);
const poolDaily = await getPoolDaily(pool);
console.log( { stakedValue, poolDaily }) // all good here and printing what it has to print
return { stakedValue, poolDaily };
};
return loadingStakingData();
});
Promise.all(data).then((values) => {
console.log('value', values) // not logging anything here
setStakingData(values);
}); // always an empty array
Any idea why this is happening?
You might be returning a pending promise in the map function. Maybe try this code instead to return the value
const data = mainnet.FairLaunch.pools.map(async (pool) => {
const stakedValue = await getStakeValue(pool);
const poolDaily = await getPoolDaily(pool);
console.log( { stakedValue, poolDaily }) // all good here and printing what it has to print
return { stakedValue, poolDaily };
});
Promise.all(data)
.then((values) => {
console.log('value', values)
setStakingData(values);
})
.catch(console.error) // Remember to catch errors!!!

Multiple nested axios calls don't resolve as expected

As described in comments between my code snippet, the asynchronicity is not working as expected. For each id, an object/item should return but it only returns one item since my async await isn't implemented properly. What could be a possible workaround?
Thanks in advance
useEffect(() => {
axios.get('url-here').then((res) => {
res.data.favProperties?.map((el) => {
console.log(el) // this returns multitple id's of saved/liked items
axios.get('url-here').then(async (r) => {
if (r.data) {
console.log(r.data) // Problem starts here
// This returns the full object of the liked items
// But only one object is returned, not every object for which an id was stored
await storageRef
.child(r.data.firebaseRef + '/' + r.data.images[0])
.getDownloadURL()
.then((url) => {
// Here i need to fetch the image for each object
console.log(url)
})
.catch((err) => console.log(err))
}
})
})
})
}, [])
I think breaking down your operations into functions will prevent this Promise Hell. I would recommend using async await for these kinda operations. Also I was confused about the last part of console logging the download URL, by my guess you're trying to save all the download URLs for these liked items in an array.
useEffect(() => {
firstFunction();
}, []);
const firstFunction = async () => {
const { data } = await axios.get("url-here");
const favProperties = data.favProperties;
const fetchedUrls = await Promise.all(
favProperties?.map(async (el) => (
await secondFunction(el.id) /** use el to pass some ID */
))
);
};
const secondFunction = async (someId) => {
/** your second URL must point to some ID (or some parameters) specific API otherwise
running same op in a loop without variations doesn't make any sense */
const { data } = await axios.get(`some-other-url/${someId}`);
if (data) {
console.log(data);
const fetchedUrl = await storageThing(data);
return fetchedUrl;
}
};
const storageThing = async ({ firebaseRef, images }) => {
try {
const downloadURL = await storageRef
.child(firebaseRef + "/" + images[0])
.getDownloadURL();
console.log(downloadURL);
return downloadURL;
} catch (error) {
console.log(error);
return '';
}
};

React - fetch data and store in a variable

Beginner with react and struggling with something that I am sure is probably very simple. I am just trying to make a simple component that will fetch data and display a part of it in a div. I am able to get the data and print it to console, but I am having trouble saving to a variable and displaying it. Here is my code (removed the actual url for privacy reasons):
let x = -1;
function getData(apiUrl){
fetch(apiUrl, {credentials: 'same-origin'})
.then((response) => {
if (!response.ok) {
Logging.error(`Did not get an ok. got: ${response.statusText}`);
}
return response.json();
})
.then(json => {x = json.value})
.catch((error) => {
Logging.error(`Error getting ad data: ${error.message}`);
})
}
const MyPage = () => {
getData('my endpoint')
return (
<div>{x}</div>
);
}
My issue is when I load the page it always displays my default value of "-1". So either x is never getting re-assigned, or the return is happening before it does.
Other commenters about setting state is not wrong.
However, you are also not exactly wrong, expecting a value for x.
Your getData function calls fetch, however you did not return anything from fetch. If you want to use x = getData(), you will need to ensure to add a return before the fetch function in order to return the data.
const getData = (apiUrl) => {
return fetch(apiUrl, {credentials: 'same-origin'})
.then((response) => {
if (!response.ok) {
Logging.error(`Did not get an ok. got: ${response.statusText}`);
}
return response.json();
})
.then(json => {x = json.value})
.catch((error) => {
Logging.error(`Error getting ad data: ${error.message}`);
})
}
let x = await getData(apiUrl)
However, fetch is asynchronous so it's you need to use x = await getData().
You cannot use await outside an async function, so you need to use effect, and useState to properly render the data you want.
import React, { useEffect, useState } from 'react';
const MyPage = () => {
const [ data, setData ] = useState();
useEffect(() => {
getData(apiUrl);
},[])
const getData = async (apiUrl) => {
fetch(apiUrl, {credentials: 'same-origin'})
.then((response) => {
if (!response.ok) {
Logging.error(`Did not get an ok. got: ${response.statusText}`);
}
return response.json();
})
.then(json => setData(json)) //setData here
.catch((error) => {
Logging.error(`Error getting ad data: ${error.message}`);
})
}
return (<pre>{ JSON.stringify(data, null, 4)}</pre>)
}
You need to use JSON.stringify to show your JSON results in your return statement.
You need to you use the state in react. Try something like:
import react, { useState, useEfect } from 'react';
const MyPage = () => {
const [data, setData] = useState(null);
const useEfect(() => {
const result = getData('my endpoint');
setData(result);
}, []);
return (
<div>{data}</div>
);
}

Resources