Next.js Discord

Discord Forum

Fetching static data in a client component

Answered
lyingcap posted this in #help-forum
Open in Discord
I'm trying to fetch some data from my database to load a dropdown menu, but it is in a client component.

I want to display it when the user click on the plus button, showing the option bellow that.

There is a way to use it just like an server component, to build a function and call it in the component?
Answered by Rafael Almeida
the mental model here is that you only use a client component for something that is interactive, but it should still render the rest of the stuff as children so you can continue the tree with RSC
View full answer

35 Replies

I want to do it just like the doc from the nextjs site
async function getData() {
  const res = await fetch('https://api.example.com/...')
  // The return value is *not* serialized
  // You can return Date, Map, Set, etc.
 
  // Recommendation: handle errors
  if (!res.ok) {
    // This will activate the closest `error.js` Error Boundary
    throw new Error('Failed to fetch data')
  }
 
  return res.json()
}
 
export default async function Page() {
  const data = await getData()
 
  return <main></main>
}
currently I'm using a function called by the click on the plus button that fetch the data and set it in a useState
but there's a problem that the component is initialized undefined
since it is a request from an user interaction the recommended way is to create a route handler and fire a request to this new endpoint
to avoid making duplicated requests you can use a data-fetching library like swr or react-query
but the idea is that it should be renderized in the server side
since this part is static
ah ok I get what you mean, I thought you wanted to fetch the data only when opening the select
you can fetch the data in a server component and pass it to a client component via props:
async function ServerComponent() {
  const data = await getData()

  return <ClientComponent items={data.items} />
}
this can be done deeper in the components tree, as long as the component doing the fetch is a RSC it should work
I thought this, but the problem is that theres a cascade of components between the server component and this part
you see that stteper bellow that?
i'm using the auth page, that calls a Signup component (client), that renderizes this parts, everyone of this 5 parts is a diferent component
well you have two options
the best would be to reorganize these components to allow the utilization of nested RSCs, like this (simplified):
async function Page() {
  return <Signup> <YourInputServerComponent /> </Signup>

notice the input component is being rendered through the Signup component even if it is a client component, this is allowed
what you can't do is render RSC from the client components itself, which seems to be what you have at the moment, a single client component rendering everything
the other option would be just prop drilling the data through Signup and other components all the way down to your input
i dont think that organizing the components inside the page file is a good option now, I already build this thinking about it and this is the best way I got for this thing
a big mess btw
@Rafael Almeida the best would be to reorganize these components to allow the utilization of nested RSCs, like this (simplified): js async function Page() { return <Signup> <YourInputServerComponent /> </Signup> notice the input component is being rendered _through_ the `Signup` component even if it is a client component, this is allowed
I build similar to this example you gave
export default async function page({ params: { lang } }: PageProps) {
  const dict = await getDictionary(lang); // pt
  return (
    <>
      <div className="flex w-screen h-screen bg-branco dark:bg-escuro2 overflow-x-hidden">
        <div className="flex w-7/12 h-fit flex-1 flex-col m-auto justify-center px-6 py-12 lg:px-8 ">
          <div className="sm:mx-auto sm:w-full sm:max-w-sm">
            <ImmobileLogo />
          </div>

          <div className="mt-10 h-max">
            <SupabaseAuth auth={dict.auth} />
          </div>
        </div>
        <div className="hidden lg:block rounded-s-giga overflow-hidden">
          <Image
            src="assets/login/bg1.jpg"
            alt="Casa"
            width={1}
            height={1}
            className="w-full h-screen"
          />
        </div>
      </div>
    </>
  );
}
but this SupabaseAuth is the mother client component, where the signin, signup and forgetpassword components are called
I think the best option is to just prop drilling this throw the child components
thanks btw, you make me see what I was worried about
keep in mind you don't need to include the entire JSX of the page in a single file, you can move it to another component like SupabaseAuth, but it should be a RSC
the mental model here is that you only use a client component for something that is interactive, but it should still render the rest of the stuff as children so you can continue the tree with RSC
Answer
if you think this refactor would be too much work then prop drilling is a viable solution as well
the problem is on the states, I'm storing the current page that the user is in a useState and when the user click on the next button, it just change the component that renders that part
otherwise just using a client component only where there has interaction should've been easy
ah I see, yeah this situation is a bit tricky, I didn't do anything similar yet to give you a proper solution
the first thing that would come to my mind is feeding the client component different JSX for each page through props then you can render them conditionally based on the state:
<SupabaseAuth auth={...} firstPage={<FirstPageRSC />} secondPage={<SecondPageRSC />} />
there might be better solutions tho, but if you don't have the time just prop drill as you said :blobthumbsup:
in this case the SupabaseAuth is a server component?
its a client component that renders the props based on its internal state
(fyi I haven't tested this so I am not 100% sure it works with the conditional rendering of the client component)