Using `Suspense` & `@tanstack/react-query` to handle loading & state is great for the most part because it isn't something that you need to keep in mind when writing your components. However, that means that it's easy to forget about it and not realise that you're making many requests, each potentially water-falling into each other, and slowing down the initial load time of the page. While most things will simply require you to solve the problem to make it better, there are some strategies might be useful if you run into this problem. ## Preventing waterfalls Almost all of the data fetching we do is done with the `fetch-on-render` strategy. When a component is rendered, it will kick off the request, wait for it to finish and then render the component. This makes sense, how would you know what to get before you know what to render? However, this means that if you have a component that renders many other components, each of which make a request, those requests won't start until the parent component has finished rendering. This can cause a waterfall effect where each request has to wait for the previous one to finish before it can start. There are a couple ways to try and prevent this. The first is to see if you're doing something like this: ```tsx const List = () => { const [items] = useItems(); return ( <div> {items.value.map(item => ( <Card key={item.id} id={item.id} /> ))} </div> ); }; const Card = ({ id }) => { const [item] = useItem(id); const [thumbnail] = useThumbnail(id); return ( <div> <p>{item.name}</p> <img src={thumbnail.value} /> </div> ); }; ``` This looks like somewhat sensible code but it's actually causing a significant waterfall. The `List` component will render, kick off the request for the items, wait for it to finish and then render the `Card` components. Each `Card` component will then kick off the request for the item and the thumbnail, wait for them to finish and then render the component. Nothing will be shown until all the requests have finished. In this circumstances, you should look to see if the initial request you make can be a larger, more efficient, `/children` request. ```tsx const useItemsWithThumbnails = () => { return useResource(client => client .api<DriveItem[]>(`/drives/${driveId}/items/${folderId}/children`) .expand(['thumbnails']) .select(['id', 'name', 'thumbnails']) ); }; const List = () => { const [items] = useItems(); return ( <div> {items.value.map(item => ( <Card key={item.id} item={item} /> ))} </div> ); }; const Card = ({ item }) => { return ( <div> <p>{item.name}</p> <img src={item.thumbnail.value} /> </div> ); }; ``` ## Make sure you're not overfetching By default, the Microsoft Graph client library will return all the fields on a resource. This is great because it means you don't need to worry about what fields you're selecting, but it also means that you're fetching a lot of data that you might not need. In situation where you're finding that you're fetching a lot of data that you don't need, you should look to see if you can select only the fields you need. ## Choose better `Suspense` boundaries By default, we normally have a top level `Suspense` boundary that will catch any loading state but that means that everything will need to load before anything is shown. If you have components that are "below the fold", i.e. not visible on the screen when the page loads, you can add a new `Suspense` boundary to that component to prevent it from blocking the initial load. You don't want to do too much of this as it can cause a lot of flickering and loading spinners but it can be useful in some situations.