Here we use the
useEffect hook to load data from an endpoint after the component renders.
On lines #7 and #8 we store the data state and the loading state. We could simplify this pattern by only keeping track of
data, and using it to determine whether to render a loading indicator or not (see below). In general though, it's a good idea to keep track of the loading state separately, such as in cases where you might want to refetch the data, for example.
We use the
useEffect hook to fetch data after the component renders. We pass an empty array
 on line #22 to indicate to the
useEffect hook that it should only run once on render, since we don't want to fetch the data multiple times (though your usecase might be different).
Since data fetching is generally an asynchronous operation, we must fetch and await the data before updating the component state. The
useEffect hook cannot have an
async function passed to it, so we must define an
fetchData on line #14 which is then called inside the hook on line #21.
Once the data is successfully fetched, we update the data and loading states (lines #17 and #18).
Not covered here is error handling, in events where the API returns an error response. In this case you might want to keep track of the error state of the component and, if there is an error, render a component that appropriately displays the error.
Here, we render a loading indicator
MyLoadingIndicator is our loading state
isLoading is still true. Otherwise, we return a component which handles displaying the fetched
Max Rozen has a blog post which goes over this pattern in more detail.