Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React useEffect hook and Async/await own fetch data func?

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?

like image 354
Milosh N. Avatar asked Mar 05 '19 17:03

Milosh N.


People also ask

Can we use async await with the useEffect hook?

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!

How do I useEffect to fetch data?

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.

What is the correct approach to fetch the data using useEffect hook?

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.

Can useEffect return a Promise?

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.


2 Answers

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>;
};
like image 52
Pavel Ye Avatar answered Oct 23 '22 22:10

Pavel Ye


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));
  });
}
like image 6
Thulani Chivandikwa Avatar answered Oct 23 '22 22:10

Thulani Chivandikwa