Next.js Discord

Discord Forum

How do i show loading spinner while my client component renders?

Unanswered
Red imported fire ant posted this in #help-forum
Open in Discord
Red imported fire antOP
Ok title is not so much self explanatory. So i am fetching data in the async page and passing data to client component. The thing is page uses searchParams and fetches data and client component does change searchParams. I want to show some loading in partial(Table Component) not the entire page

export default async function Page({ searchParams }) {
  const filters = getFiltersFromSearchParams(searchParams);

  const posts = await fetchJobPosts(
    filters,
    data.number_of_posts_per_page,
    searchParams["page"] || 1,
  );

  return (
    <div>
        <div className="job-vacancies__filters">
          <div className="container">
            <Filter {...posts} /> // this also changes searchParams too.
            <Suspense fallback={<LoadingSpinner />}>
              <Table posts={posts} />
            </Suspense>
          </div>
    </div>
  );
}


Table.js:

const Table = ({ posts }) => {
  const searchParams = useSearchParams();
  const router = useRouter();

  const handlePageChange = (page: number) => {
    const queryParams = new URLSearchParams(searchParams);
    queryParams.set("page", page.toString());
    router.push(`/?${queryParams.toString()}`);
  };

  if (loading) {
    return <LoadingSpinner />;
  }

  return posts?.data ? (
    <div className={"jobs_vacancie__posts-body"}>
      <div className="container">
        {posts?.data.map((elem) => <JobPost key={elem.id} post={elem} />)}

        <Pagination
          pagination={posts?.pagination}
          handlePageChange={handlePageChange}
        />
      </div>
    </div>
  ) : null;
};

6 Replies

@Red imported fire ant Ok title is not so much self explanatory. So i am fetching data in the async page and passing data to client component. The thing is page uses searchParams and fetches data and client component does change searchParams. I want to show some loading in partial(Table Component) not the entire page js export default async function Page({ searchParams }) { const filters = getFiltersFromSearchParams(searchParams); const posts = await fetchJobPosts( filters, data.number_of_posts_per_page, searchParams["page"] || 1, ); return ( <div> <div className="job-vacancies__filters"> <div className="container"> <Filter {...posts} /> // this also changes searchParams too. <Suspense fallback={<LoadingSpinner />}> <Table posts={posts} /> </Suspense> </div> </div> ); } Table.js: js const Table = ({ posts }) => { const searchParams = useSearchParams(); const router = useRouter(); const handlePageChange = (page: number) => { const queryParams = new URLSearchParams(searchParams); queryParams.set("page", page.toString()); router.push(`/?${queryParams.toString()}`); }; if (loading) { return <LoadingSpinner />; } return posts?.data ? ( <div className={"jobs_vacancie__posts-body"}> <div className="container"> {posts?.data.map((elem) => <JobPost key={elem.id} post={elem} />)} <Pagination pagination={posts?.pagination} handlePageChange={handlePageChange} /> </div> </div> ) : null; };
I like to use client side libaries like react query or swr. With these you get a variable like isLoading. With that you can manage how to display stuff
Red imported fire antOP
@B33fb0n3 thanks for the reply. If using react query what about the SSR ?
you can create a Loading.tsx file learn more about this here https://nextjs.org/docs/app/building-your-application/routing/loading-ui-and-streaming
@Red imported fire ant <@301376057326567425> thanks for the reply. If using react query what about the SSR ?
it's the same. When you have already have a client component, you can just use it. It's no difference between having a client compopnent or having a client component with react query
@Red imported fire ant Ok title is not so much self explanatory. So i am fetching data in the async page and passing data to client component. The thing is page uses searchParams and fetches data and client component does change searchParams. I want to show some loading in partial(Table Component) not the entire page js export default async function Page({ searchParams }) { const filters = getFiltersFromSearchParams(searchParams); const posts = await fetchJobPosts( filters, data.number_of_posts_per_page, searchParams["page"] || 1, ); return ( <div> <div className="job-vacancies__filters"> <div className="container"> <Filter {...posts} /> // this also changes searchParams too. <Suspense fallback={<LoadingSpinner />}> <Table posts={posts} /> </Suspense> </div> </div> ); } Table.js: js const Table = ({ posts }) => { const searchParams = useSearchParams(); const router = useRouter(); const handlePageChange = (page: number) => { const queryParams = new URLSearchParams(searchParams); queryParams.set("page", page.toString()); router.push(`/?${queryParams.toString()}`); }; if (loading) { return <LoadingSpinner />; } return posts?.data ? ( <div className={"jobs_vacancie__posts-body"}> <div className="container"> {posts?.data.map((elem) => <JobPost key={elem.id} post={elem} />)} <Pagination pagination={posts?.pagination} handlePageChange={handlePageChange} /> </div> </div> ) : null; };
try
async function Content({ searchParams }) {
  const filters = getFiltersFromSearchParams(searchParams);

  const posts = await fetchJobPosts(
    filters,
    data.number_of_posts_per_page,
    searchParams["page"] || 1,
  );

  return (
    <>
      <Filter {...posts} />
      <Table posts={posts} />
    </>
  );
}

export default function Page({ searchParams }) {
  // when this value is updated, the loading state will
  // be retriggered. so use things like
  // const uniqueKey = `${searchParams.query}-${searchParams.page}`
  // or just
  const uniqueKey = JSON.stringify(searchParams);
  return (
    <div>
      <div className="job-vacancies__filters">
        <div className="container">
          <Suspense
            key={uniqueKey}
            loading={<LoadingSpinner />}
          >
            <Content />
          </Suspense>
        </div>      
      </div>
    </div>
  );
}
@Red imported fire antsolved?