1

In my React functional component, I have the following code;

const user = useFetch('api/userinfo', {});

Essentially, this is a custom hook call and internally it has a fetch call to the API and sets the data (below is relevant code inside usefetch);

const [data, setData] = useState(initialData);
//....fetch call
setData(json); // once data is fetched

In my main component, since my grid depends on this data, how do I make the code wait to proceed to the Grid jsx till data is fetched? I was planning to use async..await. But not sure if it is possible to do that here with custom hooks?


With below code, seems like the hooks is getting invoked multiple times for some reason;

export default function useFetch(initialUrl, initialData) {
  const [url] = useState(initialUrl);
  const [loadingData, setLoadingData] = useState(true);
  const [data, setData] = useState(initialData);
  useEffect(() => {
    setLoadingData(true);
    fetch(url)
      .then(response => {
        if (response.status === 200) {
          response.json().then(json => {
            setData(json);
            setLoadingData(false);
          });
      })
  }, [url]);

  return [loadingData, data];
}
1
  • I would set a loading state, setting it to true once the fetch starts and setting it to false once the data is successfully fetched or there is an error. and then in your jsx don't display the grid until the loading state is false Commented Jun 3, 2021 at 14:49

2 Answers 2

2

Here's how you can do it with your custom hook:

// defining useFetch hook
const useFetch = (url) => {
  // state to keep track of loading
  const [loadingData, setLoadingData] = useState(false);

  // state for data itself
  const [data, setData] = useState(null);

  // effect to fetch data
  useEffect(() => {
    const fetchData = async () => {
      try {
        // set data to loading
        setLoadingData(true);

        // request to load data, you can use fetch API too
        const { data } = await axios.get(url);

        // set data in state and loading to false
        setLoadingData(false);
        setData(data);
      } catch (error) {
        console.log("error", error);
      }
    };

    fetchData();
  }, [url]);

  // return the data and loading state from this hook
  return [loadingData, data];
};

Now, you can use this hook in your component like:

const MyComponent = (props) => {
  const [isDataLoading, data] = useFetch('/api/some-url');

  // now check if data is loading, if loading then return a loader/spinner
  if (isDataLoading || !data) return <p>Data is loading...</p>

  // otherwise render your actual component
  return (
    <div>
      <h1>This is my component with data</h1>
    </div>

  );
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks a lot...but for some reason, the hooks is getting invoked multiple times for some reason....Added entire code in the main question....Not sure if I am doing something wrong...
@testndtv first of all you have a syntax error in your useEffect, fix it and it should work fine. And why are you using useState for url in your hook? I think there is no need for that. I haven't tested the code above ^ when I wrote it but just tested it and working fine
1

A couple options for you:

  1. Use another state variable (ie some boolean) and use that to keep track of whether or not the data comes back from the API. Then conditionally render some 'loading' element

  2. Check to see if the data exists and conditionally render based on its existence.

2 Comments

Thanks a lot. Would that another state variable be inside the custom hook code? Any reference would be really helpful.
No the other state would be in the component waiting for the hook

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.