General Help Around Fetching on the Client with Suspense
Unanswered
Silver Fox posted this in #help-forum
Silver FoxOP
hi there!
I'm learning Next.js, and I wanted to ask for some help and guidance on how I should approach fetching data on the client with Suspense.
So, let's say I have a client component and I want to fetch some data (based on some user interaction). Next.js recommends the
Cool! Let's start using useSWR. I follow the docs, and I set it up and it works! Now of course, to enhance the UX, I want to surround my client component with
This is where the difficulty starts.
Turns out, you need to enable suspense mode on useSWR. You also need fallback data... Then I dived into data URLs and placeholder images and I just thought it can't be that difficult...
Then, I turned towards React Query. Got it setup and it ofc fetches the data I want! Now, to use it with
Turns out, Next.JS is rendering my client component on the server, so
That's when I fell into the Tanstack rabbit hole of using some experimental nextjs packages and streaming and all that jazz, but I still got the same error.
Obvious solution? Disable SSR. Ok, so let's import the component dynamically.... and
So, I came here to ask for help because I can't imagine many people are facing the same issue, which tells me that I got lost in the way somehow and I probably wanna do something else.
TLDR: Trying to fetch data on the client with
I'm learning Next.js, and I wanted to ask for some help and guidance on how I should approach fetching data on the client with Suspense.
So, let's say I have a client component and I want to fetch some data (based on some user interaction). Next.js recommends the
use hook, or using libraries like useSWR or React Query, which come with bonus features like deduping network requests . Cool! Let's start using useSWR. I follow the docs, and I set it up and it works! Now of course, to enhance the UX, I want to surround my client component with
Suspense and return a fallback while I'm fetching the data. This is where the difficulty starts.
Turns out, you need to enable suspense mode on useSWR. You also need fallback data... Then I dived into data URLs and placeholder images and I just thought it can't be that difficult...
Then, I turned towards React Query. Got it setup and it ofc fetches the data I want! Now, to use it with
Suspense, you need to use the alternative useSuspenseQuery. Ok, easy enough. But, when I run the dev server (pnpm run dev), I get the error that /api/xxxx is not a valid URL.Turns out, Next.JS is rendering my client component on the server, so
useSuspenseQuery is fetching from /api/xxxx on the server, which doesn't really exist yet. That's when I fell into the Tanstack rabbit hole of using some experimental nextjs packages and streaming and all that jazz, but I still got the same error.
Obvious solution? Disable SSR. Ok, so let's import the component dynamically.... and
Suspense stops working.So, I came here to ask for help because I can't imagine many people are facing the same issue, which tells me that I got lost in the way somehow and I probably wanna do something else.
TLDR: Trying to fetch data on the client with
Suspense and it turned out more difficult than expected. So, I'm asking if I should probably be doing something differently...5 Replies
This is the simplest way imo.
Use regular
For example
Use regular
useQuery from TanStack query and instead of using Suspense just do some condtional rendering within the component.For example
"use client";
export default function UsersRooms() {
const { data: res, isLoading } = useQuery({
queryKey: ["rooms"],
queryFn: () => api.user.rooms.get(),
});
return (
<aside className={styles.aside}>
<p>
{isLoading
? "Loading rooms"
: res?.data?.rooms.length === 0
? "No open rooms"
: "Open Rooms"}
</p>
{/* Render list */}
</aside>
);
}@Jesse This is the simplest way imo.
Use regular `useQuery` from TanStack query and instead of using Suspense just do some condtional rendering within the component.
For example
tsx
"use client";
export default function UsersRooms() {
const { data: res, isLoading } = useQuery({
queryKey: ["rooms"],
queryFn: () => api.user.rooms.get(),
});
return (
<aside className={styles.aside}>
<p>
{isLoading
? "Loading rooms"
: res?.data?.rooms.length === 0
? "No open rooms"
: "Open Rooms"}
</p>
{/* Render list */}
</aside>
);
}
Silver FoxOP
hey thanks for the response! appreciate the example provided.
that definitely looks simpler to me, but doesnt that take away from some of the advantages of using Suspense, like how you can nest components within it, so you can show the fallback until all child components have resolved?
that definitely looks simpler to me, but doesnt that take away from some of the advantages of using Suspense, like how you can nest components within it, so you can show the fallback until all child components have resolved?
then u can try useSuspenseQuery and then hardcode base url
Silver FoxOP
hardcoding a url makes the code uglier (if (dev) url = .... else url = ....), and harder to maintain (you have to update the urls when it changes).
i know you're suggesting that solution because im a beginner, so it's simpler to me. but i was wondering what yall do in the same scenario?
i know you're suggesting that solution because im a beginner, so it's simpler to me. but i was wondering what yall do in the same scenario?
@Silver Fox hardcoding a url makes the code uglier (if (dev) url = .... else url = ....), and harder to maintain (you have to update the urls when it changes).
i know you're suggesting that solution because im a beginner, so it's simpler to me. but i was wondering what yall do in the same scenario?
1. hardcoding URL isn't that bad you store it in public ENV variable or generate it at runtime using
2. You said
TLDR; If u really want to use Suspense then go back to useSuspenseQuery and generate url using
window.location.origin2. You said
so you can show the fallback until all child components have resolved`You can easily do the same thing with conditional rendering and it'll give u js as much flexibility if not more.
TLDR; If u really want to use Suspense then go back to useSuspenseQuery and generate url using
window.location.origin or an ENV var.