I tried to create a function for fetching data from the server, and it works. But I am not sure if that the right way?
I created a function component to fetching data, using useState, useEffect and Async/Await :
import React, { useState, useEffect } from "react";
const Fetch = () => {
const [data, setData] = useState(null);
useEffect(() => {
const fetchData = async () => {
let res = await fetch(
"https://api.coindesk.com/v1/bpi/currentprice.json" //example and simple data
);
let response = await res.json();
setData(response.disclaimer); // parse json
console.log(response);
};
fetchData();
}, []);
return <div>{data}</div>;
};
export default Fetch; // don't run code snippet, not working, this component must be imported in main
Where I am not sure is a place where to call the fetchData function. I do that inside useEffect? Right place? And, this call will happen only one? Because i use []?
Generally, how would you do something like this?
Either way, we're now safe to use async functions inside useEffect hooks. Now if/when you want to return a cleanup function, it will get called and we also keep useEffect nice and clean and free from race conditions. Enjoy using async functions with React's useEffect from here on out!
To make this useEffect useful, we'll need to: update our useEffect to pass a prop called id to the URL, use a dependency array, so that we only run this useEffect when id changes, and then. use the useState hook to store our data so we can display it later.
Put the fetchData function above in the useEffect hook and call it, like so: useEffect(() => { const url = "https://api.adviceslip.com/advice"; const fetchData = async () => { try { const response = await fetch(url); const json = await response. json(); console. log(json); } catch (error) { console.
The above piece of code will give error because the async function returns promise and the useEffect doesn't expect callback function to return promise. It should return nothing or a function.
Overall, you are heading in the right direction. For fetching data, you'd wanna use useEffect
and pass []
as a second argument to make sure it fires only on initial mount.
I believe you could benefit from decoupling fetchJson
function and making it more generic, as such:
const fetchJson = async (url) => {
const response = await fetch(url);
return response.json();
};
const Fetch = () => {
const [data, setData] = useState(null);
useEffect(() => {
fetchJson("https://api.coindesk.com/v1/bpi/currentprice.json")
.then(({ disclaimer }) => setData(disclaimer));
}, []);
return <div>{data}</div>;
};
Another option is to use a self invoking function:
const Fetch = () => {
const [data, setData] = useState(null);
useEffect(() => {
(async () => {
let res = await fetch(
"https://api.coindesk.com/v1/bpi/currentprice.json" //example and simple data
);
let response = await res.json();
setData(response);
})();
}, []);
return <div>{data}</div>;
};
The suggestion to separate out the fetch logic to a separate function is a good idea and can be done as follows:
const Fetch = () => {
const [data, setData] = useState(null);
useEffect(() => {
(async () => {
let response= await fetchData("https://api.coindesk.com/v1/bpi/currentprice.json");
setData(response);
})();
}, []);
return <div>{data}</div>;
};
const fetchData = async (url) => {
const response = await fetch(url);
const json = await response.json();
return json;
};
And yet another option is to create a wrapper function around useEffect that triggers the async function for you similar to this:
export function useAsyncEffect(effect: () => Promise<any>) {
useEffect(() => {
effect().catch(e => console.warn("useAsyncEffect error", e));
});
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With