Next.js Discord

Discord Forum

How can I show a loading state in my client component while the server component updates?

Unanswered
Highlander posted this in #help-forum
Open in Discord
Avatar
HighlanderOP
i am familiar with the pattern of lifting state up to the URL so that the queryParams force some sort of refetch in the server component, but what patterns exist to show a loading state while the server component is re-fetching?

9 Replies

Avatar
do you use server action?
Avatar
HighlanderOP
the server page (e.g. app/hello-world/[...thing]/page.tsx) is calling a server function, e.g.

export default async function Page({
  params: { thing },
  searchParams
}: PageProps) {
  // this is a server action
  const data = await getServerData(searchParams, thing)
  return (
    <ClientComponent data={data} />
  )
}

not sure if that answers your question! im relatively newer to the app router and the patterns that are "newer" in next14, so lmk if i should be learning about something else in particular
Avatar
you can use the [loading.tsx](https://nextjs.org/docs/app/api-reference/file-conventions/loading) to show a loading state for your page.

Your server request is one request from the client and the client will only see the clientcomponent (your children), after the serverside request is finished. So there isn't any way to serve it before. However: you can serve a different (loading) page to show a loading animation while the server gets the data (that's why I mentioned loading.tsx)
Avatar
HighlanderOP
@B33fb0n3 interesting! does it allow for cases like this?

export default async function Page({
  params: { thing },
  searchParams
}: PageProps) {
  // this is a server action
  const data = await getServerData(searchParams, thing)
  return (
    <>
      <ClientComponent data={data} />
      <AnotherClientComponent />
    </>
  )
}

where i can show a loading state for just ClientComponent? or does the loading state show for the entire page? (this is a very simplified example ofc)
Avatar
Your server request is one request from the client and the client will only see the clientcomponent (your children), after the serverside request is finished. So there isn't any way to serve it before. However: you can serve a different (loading) page to show a loading animation while the server gets the data (that's why I mentioned loading.tsx)
Avatar
HighlanderOP
oooo ok, thanks for that (in a meeting rn so i only glossed over your msg)
Avatar
it's fine 🙂
Take a look at the loading.js and it will solve your problem mostly
Avatar
Pharaoh Hound
If AnotherClientComponent is completely independent and doesn't need anything from data, you can just use Suspense directly. Just move the data fetching lower, add a suspense boundary :

const ServerComponent = async () => {
  const data = await fetch()
  return <div>{...}</div>
}

export default async function Page({
  params: { thing },
  searchParams
}: PageProps) {
  return (
    <>
      <Suspense fallback={<Spinner />}>
        <ServerComponent />
      </Suspense>
      <AnotherClientComponent />
    </>
  )
}


the key thing to know about loading.tsx is it just wraps your page.tsx in something like the above. If you do this, on initial render the user will see AnotherClientComponent rendered and then when the fetch call succeeds, the result will be streamed in and replace your fallback with the actual component. Hope that helps! Lmk if you have any other questions.
Avatar
@Highlander solved?