swr icon indicating copy to clipboard operation
swr copied to clipboard

Parallel loading with Suspense

Open vinczemarton opened this issue 2 years ago • 2 comments

I guess this is more of a general question than a bug report, but since suspense for data fetching will be the new gold standard, it worths to clarify, or even have a documentation example on how to solve it generally.

I found this pattern what was very easy with useSWR before but with suspense I cannot figure out how to do.

I want a component to load data from 2 different endpoints paralelly. Let's say I have a publicData and privateData endpoint for a person. They both accept personId as a parameter. I want to call both at the same time and render when both arrived.

Before I could do something like this and it would load both requests parallelly:

function MyComponent() {
  const { data: publicData } = useSWR("https://publicDataUrl/", fetcher);
  const { data: privateData } = useSWR("https://privateDataUrl", fetcher);

  if (!publicData || !privateData) return "Loading...";
  return (
    <div>
      <h1>{publicData.name} ({privateData.socialSecurityNumber})</h1>
      <p>{publicData.description}</p>
    </div>
  );
}

Now with suspense I can restructure this to move out the loader to somewhere else and data will be always available inside:

function MyComponent() {
  const { data: publicData } = useSWR("https://publicDataUrl/", fetcher, { suspense: true });
  const { data: privateData } = useSWR("https://privateDataUrl", fetcher, { suspense: true });

  return (
    <div>
      <h1>{publicData.name} ({privateData.socialSecurityNumber})</h1>
      <p>{publicData.description}</p>
    </div>
  );
}

function OuterComponent() {
  return (
    <Suspense fallback="Loading ...">
      <MyComponent />
    </Suspense>
  );
}

Very cool. But I have noticed that privateData waits for publicData to load. Look at this sandbox where the issue is visible (refresh, and see the console on what runs when): https://codesandbox.io/s/heuristic-shape-4pbw5?file=/src/App.js

Sure I could try to split it into 2 different component, and move the data loads to their respective components (like here: https://codesandbox.io/s/quirky-lewin-prw2w?file=/src/App.js ), but that is not always feasible. Sometimes there can be a component that needs data from the 2 different requests, like in the private/public data code example I provided in this issue.

The best I could figure out is to call useSWR in the top component without suspense and ignore their return value, and call with suspense inside the components, but it feels duplicated and weird: https://codesandbox.io/s/nice-rubin-3g9of?file=/src/App.js

Is there a better way to do this?

vinczemarton avatar Dec 19 '21 22:12 vinczemarton

You can take a look at #168 and all the related discussions. A temporary solution can be:

useSWR("https://publicDataUrl/", fetcher) // preload
useSWR("https://privateDataUrl", fetcher) // preload
const { data: publicData } = useSWR("https://publicDataUrl/", fetcher, { suspense: true })
const { data: privateData } = useSWR("https://privateDataUrl", fetcher, { suspense: true })

shuding avatar Dec 20 '21 11:12 shuding

That is the idea in my third sandbox except that I can do it in the same component. Thanks a lot! I hope you figure out the best api for this soon.

vinczemarton avatar Dec 20 '21 17:12 vinczemarton

https://swr.vercel.app/blog/swr-v2.en-US#preloading-data

promer94 avatar Jun 07 '23 12:06 promer94