Next.js Discord

Discord Forum

Client Side Data Loading

Unanswered
Asiatic Lion posted this in #help-forum
Open in Discord
Asiatic LionOP
Is there a way to do a getServerSideProps-like initial data fetch for client components with the app router?

44 Replies

Sun bear
I would recommend to use server components and then you can super simple fetch the data.

If you need it in a client component i would fetch it in a server conponent and give the props to tge client component
@Sun bear I would recommend to use server components and then you can super simple fetch the data. If you need it in a client component i would fetch it in a server conponent and give the props to tge client component
Asiatic LionOP
the problem is this pattern breaks doesn't work when you have a client component that needs to render another data-fetching component
since you can't have a server component be a child of a client component
You can do slots and conditional rendering based on url hardcoding a client component into a template and then having the child be a route but this becomes insane quickly
@Asiatic Lion the problem is this pattern breaks doesn't work when you have a client component that needs to render another data-fetching component
Bengal
well then if you don't want to have server component slots in ur client side component, then yeah use react query
@Bengal well then if you don't want to have server component slots in ur client side component, then yeah use react query
Asiatic LionOP
well its that slots aren't meant for tightly coupled nesting (e.g. when the parent component passes props about what to fetch to the client)
Asiatic LionOP
Like you have a parent component get a list of departments, and then have each row in a table show a few courses. The row component ideally fetches its own data based on the department id you pass in as a prop
Maybe I have the wrong architecture overall and should do fetching of large objects and pass them down instead of multiple round trips but I'm not sure. feels like the beneift of react is having logic (including CRUD) colocated with the presentation layer on each chunk of the app
Bengal
ok sure have ur slot accept a function that renders a reactnode
type Props = {
    course: (courseId: number) => React.ReactNode
}

const NestedServerSideComponent = ({courseId}: {courseId:number) => <div>{courseId}</div>

const ClientSideComponent = ({course}: Props) => {
    const id = 5
    return course(5)
}

const ParentServerSideComponent = () => <ClientSideComponent course={(courseId) => <NestedServerSideComponent  courseId={courseId}/>} />
I'm actually not entirely sure how the server component would fetch server side first if the courseId is given client side.. maybe it works maybe it doesnt eh
pre sure nextjs fetch caching sth sth can do what ur after but i'm not too sure
@Bengal I'm actually not entirely sure how the server component would fetch server side first if the courseId is given client side.. maybe it works maybe it doesnt eh
Asiatic LionOP
you could do weird stuff with query params, other url statefulness, or even like cookies (basically any way to encode state outside of react in a way that gets sent to the server so that the server can then figure out what to render for a client) but the ideal situation would be that there is a way to have a data loading framework capability that lives on the server and can pass data to the client component as well as other child components
Bengal
i mean a rudimentary solution would be to have a context that fetches and then use that
Asiatic LionOP
wdym a context?
Bengal
like react context
Asiatic LionOP
yea but that doesn't live on the server
Bengal
yeah ur right i guess there rly isnt anything for stuff like this yet huh
I mean what u could do
is fetch everything in the top level server component
its cached
then in every child component use the same fetch call
use typescript to filter out and specify for only that component's dependencies
instead of
function Page() {
  return <Table />
}

"use client"
function Table() {
  return everything
}

use
function Page() {
  return (
    <Table>
      <TableHeader>...</TableHeader>
      <TableRow>...</TableRow>
      ...
    </Table>
  )
}

then Table can be a client component while TableHeader and TableRow can still be server components if you want
@joulev instead of tsx function Page() { return <Table /> } "use client" function Table() { return everything } use tsx function Page() { return ( <Table> <TableHeader>...</TableHeader> <TableRow>...</TableRow> ... </Table> ) } then `Table` can be a client component while `TableHeader` and `TableRow` can still be server components if you want
Asiatic LionOP
ok but what if I want table to have some related text that depends on the number of rows the table has. Table needs to pass a prop into that component so it knows what table it is or at least how many rows it has. I'd prefer to just be able to pass some sort of table id into this component and it figures out the number of rows itself
@Bengal I'm actually not entirely sure how the server component would fetch server side first if the courseId is given client side.. maybe it works maybe it doesnt eh
Asiatic LionOP
times like this is when I wanna use webflow for the landing page and then just use next fully client side as an overweight routing library
@Bengal I'm actually not entirely sure how the server component would fetch server side first if the courseId is given client side.. maybe it works maybe it doesnt eh
Asiatic LionOP
I don't think this works because props need to be serializable afaik and functions aren't
@Bengal is fetch everything in the top level server component
Bengal
yeah this then
@Asiatic Lion ok but what if I want table to have some related text that depends on the number of rows the table has. Table needs to pass a prop into that component so it knows what table it is or at least how many rows it has. I'd prefer to just be able to pass some sort of table id into this component and it figures out the number of rows itself
async function TableRowCount({ id }) {
  const count = await getRowCount(id);
  return count;
}

function Page() {
  const id = getFromSomewhere()
  return (
    <Table>
      <TableHeader>...</TableHeader>
      <TableRow>...</TableRow>
      <TableRowCount id={id} />
    </Table>
  )
}
if a component needs something, the data that it needs must be available to it. in your case, the number of rows component needs the entire row data. so all rows have to be fetched in a server component above it. so you fetch all rows above it and pass the data via props.

this is just how server-side rendered apps work. none of this is related to nextjs.
Asiatic LionOP
making parent components aware of client components is exactly what I'm trying to avoid
@joulev if a component needs something, the data that it needs must be available to it. in your case, the number of rows component needs the entire row data. so all rows have to be fetched in a server component above it. so you fetch all rows above it and pass the data via props. this is just how server-side rendered apps work. none of this is related to nextjs.
well whatever you do. this is a hard truth you must deal with.

you need the total number of rows, you have to fetch it somewhere up the tree. could be just a sql COUNT, but could also be simply fetching all rows and pass that object as a prop.
(about getServerSideProps: it's equivalent to the option of fetching everything in the root server component and then pass it as props to children components, by the way. it won't do better than what we have here.)
feel like you are just asking for something that's theoretically impossible
@joulev well whatever you do. this is a hard truth you must deal with. you need the total number of rows, you have to fetch it somewhere up the tree. could be just a sql `COUNT`, but could also be simply fetching all rows and pass that object as a prop.
Asiatic LionOP
The thing is I don't need the total number of rows (list of courses), I just need some piece of information that will let me get the total number of rows (department id). This isn't a components must be able to know what data render without passing it in issue, it's a components should be able to get the data they need to render based on piece of information that is passed in.
@joulev feel like you are just asking for something that's *theoretically* impossible
Asiatic LionOP
prob not impossible. Would need to just make explicit the type of data that a child expects, fetch/create it in a server side data function, pass that data to the server side data function of the child component as well as to whatever the current component components needs for its own non-child rendering, and then associate which call of the child data fetch/render function was assocaited with which call of the parent data function to slot the child component in
the problem is this creates a data waterfall which becomes inpreformant without enough prefetching based on expected values (sort of what @Bengal was talkin about)
the original question wasn't even really about this kind of stuff (even though its related), it how can you have a client function fetch data (efficient in terms of loc not anything else) so that you didn't need to make a slot to render it
i really don't understand what you are trying to do, so i won't be able to provide more help other than the interleaving link above.

just gonna say this:
* server components are simply () => html functions
* they cannot be imported to client components because they don't run on the client
* they may be rendered as children or other props of client components completely fine
* client components cannot pass props to server components, but data can be passed from the client to the server by way of URL query params.
@joulev i really don't understand what you are trying to do, so i won't be able to provide more help other than the interleaving link above. just gonna say this: * server components are simply () => html functions * they cannot be imported to client components because they don't run on the client * they may be rendered as children or other props of client components completely fine * client components cannot pass props to server components, but data can be passed from the client to the server by way of URL query params.
Asiatic LionOP
This became a discussion about initial data fetches that depend on some parameters, but the original question was about if there was a way to load data into client components that isn't wrapping them in a server function so that for child client components you don't have to also wrap them in a server component and then use slots and can just directly import the child component. It sounds like there isn't and you have to use slots, not have client components, or not have server components and fetch data fully client side