Call API only after setting loading state - reactjs

Since, setState in a functional component do not return a promise, how do we set a loading state and then call an API. I have seen people doing it like the one below. I think the axios call will not wait for the loading state to be successfully set before executing. Is there any other better way to solve this without writing the fetch part in an useEffect with the dependency of the loading state?
useEffect(() => {
const fetchProduct = async () => {
setLoading(true);
try {
const response = await axios('http://localhost/products');
setData(response.data);
} catch (err) {
setError(err);
}
setLoading(false);
};
fetchProduct();
}, [productId]);

you can try something like this
useEffect(() => {
const fetchProduct = async () => {
setLoading(true);
await axios.get('http://localhost/products')
.then(response => {
setLoading(false);
setData(response.data);
}).catch(error => {
setLoading(false);
setError(error);
})
};
fetchProduct();
}, [productId]);

Related

How to fetch obects from an api call with react hooks

I want to fetch data from an api endpoint using custom hooks and axios in React.
const [data, setData] = useState({});
const fetchData = async () => {
try {
const res = await axios.get(`apiUrl`, {
console.log(res.data);
});
console.log(res.data);
//not working
setData(res.data);
} catch (error) {
console.error(error);
}
}
useEffect(() => {
fetchData();
},[{}]);
res.data is returning an object as you can see in the image below.
When I try to set the data into the local state with the react hook useEffect its returning an endless loos when printing out data.
Any help is appreciated. Thanks in advance.
You have an error in the dependency array. fetchData is a dependency, so it should be there. To assure fetchData has a stable reference, wrap it in useCallback, like this:
const fetchData = useCallback(async () => {
try {
const res = await axios.get(`apiUrl`, {
console.log(res.data);
});
console.log(res.data);
setData(res.data);
} catch (error) {
console.error(error);
}
}, []);
useEffect(() => {
fetchData();
},[fetchData]);

How to get an asynchronous request from the server using Hook useEffect?

Here's how I tried to do it, but it didn't work
useEffect(() => {
try {
const response = async() => {
await axios.get('https://prectik-87c20-default-rtdb.europe-west1.firebasedatabase.app/quizes.json')}
console.log(response.data)
} catch (e) {
console.log(e);
}
})
And so it should look in class components
async componentDidMount() {
try {
const response = await axios.get('https://prectik-87c20-default-rtdb.europe-west1.firebasedatabase.app/quizes.json')}
console.log(response.data)
} catch (e) {
console.log(e);
}
}
You are defining your response as a function (that is never used) rather to do a request call .
Try to split you request function and the useEffect like this (maybe the useEffect don't permit async functions as its parameter).
Maybe this is the correct way to do what you want.
async function request(){
const response = await axios.get('https://prectik-87c20-default-rtdb.europe-west1.firebasedatabase.app/quizes.json')
console.log(response.data)
}
useEffect(async () => {
try {
request()
} catch (e) {
console.log(e);
}
})
I believe you forgat to use the response to convert it to a useable data
useEffect(() => {
try {
const response = async() => {
await axios.get('https://prectik-87c20-default-rtdb.europe-west1.firebasedatabase.app/quizes.json')}
const dataUser = await response.json(); //THIS LINE
console.log(dataUser)
} catch (e) {
console.log(e);
}
})
And so it should look in class components
async componentDidMount() {
try {
const response = await axios.get('https://prectik-87c20-default-rtdb.europe-west1.firebasedatabase.app/quizes.json')}
const dataUser = await response.json(); //THIS LINE
console.log(dataUser)
} catch (e) {
console.log(e);
}
}
I got a few examples in this Github repository
you must define a function and call it after
useEffect(() => {
const fetchData=async()=>{
try {
const response = await axios.get('https://prectik-87c20-default-rtdb.europe-west1.firebasedatabase.app/quizes.json')
console.log(response.data)
} catch (e) {
console.log(e);
}
};
fetchData();
})

How to wait for value before running fetch?

Edit: I ended up using axios instead of fetch and it works great. Just removed the response.json() and switch fetch to axios.get.
my first post here with what is probably a pretty easy question. I am trying to get the lat and long values to actually be something before being fed into the URL. Most of the time I get an error returned for a bad request because the lat and long values haven't propagated yet.
Thanks!
Code is here (edited out API keys):
const fetchData = async () => {
navigator.geolocation.getCurrentPosition(function (position) {
setLat(position.coords.latitude);
setLong(position.coords.longitude);
});
const url =
await `https://api.openweathermap.org/data/2.5/weather/?lat=${lat}&lon=${long}&units=metric&APPID=DELETED`;
await fetch(url)
.then((response) => {
return response.json();
})
.then((result) => {
setData(result);
})
.catch(console.error);
};
fetchData();
}, [lat, long]);
It seems that lat and long are set in the useEffect using them. You should probably set them before using them in another useEffect.
useEffect(() => {
navigator.geolocation.getCurrentPosition(function (position) {
setLat(position.coords.latitude);
setLong(position.coords.longitude);
});
}, [])
useEffect(() => {
const fetchData = async () => {
const url = `https://api.openweathermap.org/data/2.5/weather/?lat=${lat}&lon=${long}&units=metric&APPID=DELETED`;
await fetch(url)
.then((response) => {
return response.json();
})
.then((result) => {
setData(result);
})
.catch(console.error);
};
if (lat && long) {
fetchData();
}
}, [lat, long]);
Either you have to store those values in your function or you have to wait until the state is updated. State is asynchronous and this is why you get this error.

Axios await axios.get() not honored in a useEffect(, []) sequence with multiple operations

I have a useEffect(.., []) initialization sequence which involves 2 operations, each an await-blocked sync Axios call.
I verified that the 1st Axios call await call is not honored and the flow jumps to the 2nd useEffect operation, getFlag(), right after the await axios.get() line. Does anyone know why?
useEffect(() => {
getAgreements(); // Step 1
getFlag(); // Step 2
}, []);
const getAgreements = async () => {
const url = '/getAgreements';
try {
const response = await axios.get(url); // This 'await' is not honored, jumps to getFlag()
setAgreementsList(response.data);
}
catch (error) {
setErrorObj({message: error.message, location: 'Agreements.js: getAgreements'});
}
finally {
setIsLoading(false);
}
}
const getFlag = async () => {
const url = '/getNewAgreementIndicator';
try {
const response = await axios.get(url);
setNewAgreementFlag(response.data);
}
catch (error) {
setErrorObj({message: error.message, location: 'Agreements.js: getNewAgreementIndicator'});
}
finally {
setIsLoading(false);
}
}
When I rewrite the code below with .then() I see that in the 2nd fetch, the await is not honored, and it goes to console.log() before the result of the 2nd fetch is returned. Can anyone clarify?
useEffect(() => {
getAgreements()
.then(() => {
getFlag()
})
.then(() => {
console.log('test');
})
}, []);
Wouldnt it be better to just have 2 use effects rather than all of them in the one that happens on mount? Have another useEffect which gets triggered when the agreementsList gets update
useEffect(() => {
getAgreements(); // Step 1
}, []);
useEffect(() => {
if(agreementsList){
getFlag(); // Step 2
}
}, [agreementsList]);

How to use async function and export it correctly with React Native?

My question is about correctly implementing an async function to fetch data. I've a function called _getData() and I'm calling it on the componentDidMount() of a screen. But when server response is slow, switching to this screen is getting slower. So I would like to use async function for fetching data. But I'm not sure if I'm doing it correctly. Is that a correct approach? I can't be sure if it works async or not.
Here is my Api._getData() code:
const _getData = async () => {
return await axios.get("http://blabla.com/someservice", { params: someParamDataHere });
};
export const Api = {
_getData
};
and on SomeScreen.js, I also have loadData() function which calls the function above and does state updates.
loadData() {
Api._getData()
.then((response) => {
this.setState({ myData: response.data });
})
.catch((error) => {
console.log(error.response);
});
}
in componentDidMount() function of the same screen I'm calling this loadData()  function directly.
Now, is it enough to declare Api._getData() as async and using await in it, or should I change some trigger functions too?
Thank you very much for your help.
instead of async await use promises
export const getRequest = (url) => {
return new Promise((resolve, reject) => {
api
.get(url)
.then((response) => {
handleReponse(response)
.then((errorFreeResponse) => {
resolve(errorFreeResponse);
})
.catch((error) => {
reject(error);
});
})
.catch((error) => {
reject(handleError(error));
});
});
};
You are doing correct while retrieving in load Data . What you can do more is try more syntactical sugar of es6 by using async await in loadData , hence
loadData = async() =>{
try{
let response = await Api._getData();
this.setState({ myData: response.data });
} catch(err){
console.log(error.response);
}
}
Hope it helps. feel free for doubts

Resources