Next.js Discord

Discord Forum

Accessing URL parameters for SSG pages requires props drilling in app dir?

Unanswered
Broad-snouted Caiman posted this in #help-forum
Open in Discord
Broad-snouted CaimanOP
Is the only way to access params in SSG pages in app dir to get them at the very root (i.e., the top-level page component)? And so if I have some deeply nested component, then my only option is to props drill it down? I suppose composition might work, as well, but I'm not confident that this won't present other issues

162 Replies

Broad-snouted CaimanOP
I need to access params throughout the page, not just at the root
I have a view which displays all the locations that match the given filters that the user has selected. This includes city + state + location type (as URL params) but also things like price, amenities, etc. (as query params)
you can only access the params of the current or previous route segments. Not after it
so if you want all the available params, you can only access it at the very LEAF of route, either at page.tsx or layout.tsx
otherwise, use Client Components
client components have the liberty to be able to access ALL params/routes/searchparams
Broad-snouted CaimanOP
In your response, are you distinguishing between search params and url params?
url params are available at the root
according to Next.js "Params" are routes implemented with Dynamic routes, such as [pageid]
while "SearchParams" are the part thats on the end bit of the url, starting with ? like ?value=key
Broad-snouted CaimanOP
Right
I'm only asking about URL params here, not search params
and not "all" params
are you referring the top to be the top of the component? not Root Layout?
as in, top level in page.tsx or layout.tsx as opposed to children components
Broad-snouted CaimanOP
My question is simply: how do I acess URL params at a leaf component? Is the only way to props drill it down from the top (page) component?
https://nextjs.org/docs/app/api-reference/file-conventions/page#params-optional shows how to get url params at the top component in SSG
So I can props drill it down to leaf components, but that's bad DX
Is there a way to get it to leaf components without props drilling it?
If you really want to access it anywhere,you can use client components
otherwise, Composition is not a bad idea
Broad-snouted CaimanOP
Client components doesn't work because then I can't use the params for e.g. db queries
you can still create and call server function from client components, then run the db queries
but thats just another way
the short answer is Composition
Broad-snouted CaimanOP
How do you call server functions from client components? I'm pretty sure that's not possible...
create the server function in another file, then import the function into the client comps
its also in the docs
maybe you haven't seen the udpated ones
Broad-snouted CaimanOP
Could you link me please?
I'm talking about querying, not server actions (mutations)
querying?
Broad-snouted CaimanOP
Getting data from the db
fetching data?
Broad-snouted CaimanOP
right
you can just cache it and reuse returned cached function at child server component :/
that way no prop drilling :D
Broad-snouted CaimanOP
Are you talking about fetch?
no
Broad-snouted CaimanOP
Is there an example somewhere of what you're talking about?
Pretty sure it's not possible to do a db query in a client component
Its in the Cachin section of the docs
Broad-snouted CaimanOP
You can do a db query directly in a server component, but not a client component
You said you weren't talking about fetch
hmm
Broad-snouted CaimanOP
oh, the cache() wrapper?
nvm
Broad-snouted CaimanOP
"We recommend using the server-only package to make sure server data fetching functions are never used on the client."
you still need the params right
Broad-snouted CaimanOP
Yeah
id just do a top-level fetch, then pass the data to a leaf component that is done using composition
im not sure why composition would bring issues, if anything it solves several issues
Spectacled bear
It's actually really helpful to build separate endpoints anyway. For one thing, you can use Postman to test your code independent of the UI, but also if you call fetch even in a server component, the result of that fetch can be cached
And once you have an endpoint, there's not a whole lot of difference between client side and server side
the point of server components is to have access to server function without creating endpoints...
@Broad-snouted Caiman API endpoints are just added complexity in the server component world where I should be able to query my db directly
Spectacled bear
It's actually simpler to break things into individual reusable pieces, especially if that increases testability
@Spectacled bear It's actually simpler to break things into individual reusable pieces, especially if that increases testability
Broad-snouted CaimanOP
You're not breaking into individual pieces, you're adding new pieces and new complexity which requires additional testing and maintenance, and largely defeating the whole benefit of server components
@Spectacled bear And once you have an endpoint, there's not a _whole_ lot of difference between client side and server side
Broad-snouted CaimanOP
There's not just a singular branch that also needs the data, there are multiple branches that need it. So I can't just use "children", I have to create slots specifically for each branch to compose. And then if I add branches, I have to add additional children slots. It's bad DX and something which imo shouldn't be the only option. Server components "know" what the dynamic path params are, there should be an easy way to access it. I'm sure next will eventually add this, just surprised it's not already there
composition... ?
Spectacled bear
The thing is, as you're discovering, it's actually really complex to get server components to work correctly. And it's fairly difficult to do e2e testing with Next 13 bc by default it hits your database during the compile phase. This makes setting up your containers a PIA
Broad-snouted CaimanOP
Although I haven't really used composition before, so maybe I'm misunderstanding it
like this
putting component inside the children of another component
but you only pass the data on the child of that component
Broad-snouted CaimanOP
Except B has descendents which also need the data -- so I'm back to props drilling again
@Spectacled bear The thing is, as you're discovering, it's actually really complex to get server components to work correctly. And it's fairly difficult to do e2e testing with Next 13 bc by default it hits your database during the compile phase. This makes setting up your containers a PIA
Spectacled bear
Creating an endpoint is super easy and quick, and it's flexible if you want to move from SSC to client side. Also, again, the result of that call will be cached by default, meaning anywhere else you use it will be super fast
wellllllllllllllllll
cache() it is then
@alfon break it down to <C> and <D> ?
Broad-snouted CaimanOP
Now I just have a bunch of child props on all my components like childComponentSlotC and childComponentSlotD -- again, bad dx
Like I said, there are multiple descendents which need the data, so I can't just use the single children prop
@Broad-snouted Caiman Now I just have a bunch of child props on all my components like `childComponentSlotC` and `childComponentSlotD` -- again, bad dx
Spectacled bear
Honestly I think Next 13 isn't going to be ready for prime time for a while--they can't decide what they want to be, which makes it bad for everyone
does the descendants use the same data or is it a transformed data of the original data?
Broad-snouted CaimanOP
It would look more like this:
<A
  childSlotB={<B data={prefetched} />}
  childSlotC={<C data={prefetched} />}>
/>
ah i see
Broad-snouted CaimanOP
except then B and C also have descendents that need to follow the same pattern
So it gets very ugly very quickly
I mean ultimately all the data is transformed into different UI chunks, so it's kinda irrelevant right? Doesn't change the problem at hand
allright
Spectacled bear
Could you use a client component to get the url params, then nest a server component inside?
i dont like saying it but id use react context
Spectacled bear
Kinda dumb, but then a lot of stuff about this is counter intuitive
@Spectacled bear Honestly I think Next 13 isn't going to be ready for prime time for a while--they can't decide what they want to be, which makes it bad for everyone
Broad-snouted CaimanOP
Yeah, tbh, if there's not a decent solution to this problem, it probably doesn't make sense for me to continue using app router, which means it doesn't make sense to keep using Next.js, which means I probably need to jump ship to astro or qwik or something
@alfon i dont like saying it but id use react context
Spectacled bear
You can't use context in a server component
I haven't tried using context to provide initial value to child components
but its really my last resort
@Spectacled bear Could you use a client component to get the url params, then nest a server component inside?
Broad-snouted CaimanOP
Could you show me an example of how this works while staying in SSG?
@Spectacled bear I was really excited by streaming html, but the more I play with Next 13 the more footguns I find
Broad-snouted CaimanOP
Yeah me too, it seemed very promising at first, but a lot of basic DX seems to be missing
otherwise, the caveat is that you really need to pass the params down
@Spectacled bear You can't use context in a server component
it doesn't have to be server components. Client components can be SSRd too. But not sure about SSR-ing react usecontext
while yall talk about this, i would like to share a package i just came across https://github.com/manvalls/server-only-context
it uses cache() 🙃
all this time
yup
so you can avoid prop drilling
curious about the .current part
what does it do specifically
wait nvm
huh neat it just caches an object as opposed to a function
quite clever
@Broad-snouted Caiman Could you show me an example of how this works while staying in SSG?
Spectacled bear
Honestly, no. I keep hitting snags in my learning project, so this is a combination I haven't played with yet.
Wouldn't a server context be shared between all users?
its already shared between all user
and SSG is only built once, at build time
this is a DX question, not a data fetching question
Guys I think we just need a global object (accessible in RSC) that contains params (and query params for that matter), like in PHP :elonTroll:
yeah
Broad-snouted CaimanOP
I mean we just need the same useParams hook that pages router has and that client components have, but in the server context, it's really not a big ask
we need context for server components in RSC
Broad-snouted CaimanOP
Yeah, something like that should be feasible too
well
I dont think its within the scope of Next.js so better head out to React Discussion page :'
so it's just logically impossible
use the package above or prop-drill
oh
I think not as powerful as useParams
@joulev it is impossible because you cannot reliably determine the params inside a layout
Broad-snouted CaimanOP
We're talking about url params (dynamic url segments), not search / query params. You can get url params at the root page component today
@alfon what do you mean?
i mean layouts are not rerendered when you navigate in routes under it, so you cannot determine the current path in the layout
@Broad-snouted Caiman I mean we just need the same `useParams` hook that pages router has and that client components have, but in the server context, it's really not a big ask
Spectacled bear
I'm pretty sure you can put a server component in a client component (check the docs), so you should be able to inject the params you get from the hook back into the server component
Nonono i get what you mean but
@joulev i mean layouts are not rerendered when you navigate in routes under it, so you cannot determine the current path in the layout
Broad-snouted CaimanOP
We're not talking about layouts, just the root page component
What we meant is that to be able to use a hook to determine the context of the current page.tsx or the current layout.tsx
so something thats within a route segment only. No time traveling xD
@Broad-snouted Caiman We're not talking about layouts, just the root page component
but you are asking for a getPathname function in server components. What if that function is used in a layout component? What do you think will that function return?
anyway I gave yall a package to not have to prop-drill, use it or prop drill
yeah we wished that it would be built in
definetly i could just copy pasted that code myself haha
@Broad-snouted Caiman We're not talking about layout components
yes but what if a user uses it in a layout component
do you understand what i mean?
Broad-snouted CaimanOP
idk, throw an error? Who cares
well i'm going bald
go argue with the nextjs team
im out of here
we are only concerned about the parameters of the function
@joulev while yall talk about this, i would like to share a package i just came across <https://github.com/manvalls/server-only-context>
Broad-snouted CaimanOP
I think this solves my problem, thanks so much!
Im sorry for making you bald, i really understand what you meant but i just wish you know what we're talking about
yes i know, i'm merely saying such an API would be logically impossible
you are talking about the ideal case of users using the getPathname function where it works
im talking about the general case of users using it where it doesn't work
hmmm
believe it or not i actually opened an issue requesting this exact API in the nextjs repo
but now i know it is logically impossible
@joulev https://github.com/vercel/next.js/issues/46618
well you should've lead with that xD
again, sorry for making you mald
well at least we have a thread that contributes well to the server insights
157 messages and counting, it's not easy to reach this number
There's also this which is still open
@joulev but now i know it is logically impossible
Broad-snouted CaimanOP
Your conclusion on that issue is different than what you're claiming here. On the thread, you concluded "there isn't much use for this feature anymore", but here you're saying "it's logically impossible". It's not logically impossible -- you linked to a library which shows how to do it. I disagree that there's "not much use" -- it solves a props drilling DX problem
@୧ʕ•̀ᴥ•́ʔ୨ https://github.com/vercel/next.js/issues/43704
yeah well you have this link over here where you can discuss this with the team directly
talking here won't do much to solve the problem and i'm just a normal nextjs user content with what i have now