https://www.theodinproject.com/lessons/node-path-react-new-fetching-data-in-react

Using custom hooks

We can separate out the fetching logic altogether into a custom hook. This will allow us to make the logic reusable and easily testable.

Here’s how we would do it for our example:

import { useState, useEffect } from "react";
 
const useImageURL = () => {
  const [imageURL, setImageURL] = useState(null);
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(true);
 
  useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/photos", { mode: "cors" })
      .then((response) => {
        if (response.status >= 400) {
          throw new Error("server error");
        }
        return response.json();
      })
      .then((response) => setImageURL(response[0].url))
      .catch((error) => setError(error))
      .finally(() => setLoading(false));
  }, []);
 
  return { imageURL, error, loading };
};
 
const Image = () => {
  const { imageURL, error, loading } = useImageURL();
 
  if (error) return <p>A network error was encountered</p>;
  if (loading) return <p>Loading...</p>;
 
  return (
    <>
      <h1>An image</h1>
      <img src={imageURL} alt={"placeholder text"} />
    </>
  );
};

https://codesandbox.io/p/sandbox/github/TheOdinProject/react-examples/tree/main/fetching-data-example?file=%2Fsrc%2FProfile.jsx%3A1%2C1&embed=1 If we remove the short-circuiting conditional that waits for imageURLBio would send a request immediately, but that would mean abandoning our loading screen. Instead of compromising on design, we can lift the request up the component tree and pass its response as a prop to Bio.

waterfall when fetching data