how to pass searchParams around in next app server components?
Hey guys, as the title says, how do you guys pass around searchParams without an incredible amount of prop drilling? I'm in a position where most of my app and fetches lives in server component land, which feels pretty ideal. The only thing is that with trees of server components, I'm forced to prop drill my params and searchParams into every component, which would've been fine, if it wasn't for the fact that there is already a solved pattern in client side react with context and stores.
Does anyone else feel this way too and/or how do you go about this?
8 Replies
Tried nuqs, but nuqs' cache doesn't update on history replace
Do you have an example where the cache didn’t update?
Did you enable sending updates to the server using
shallow: false
? By default, updates are client-side only, and opt-in to go through the network if the server needs the search params
https://nuqs.47ng.com/docs/options#shallowOptions | nuqs
Configuring nuqs
I don't think there's much you can do on server side. On client side you can use the
useSearchParams()
hook.
How much prop drilling are we talking about BTW? If this was an issue for me, I would consider trimming down the tree of server components.Yeah, this looks similar to my alternate solution to use
history.push
.
I feel like this answer to trim down the server components tree into client components is just not a scalable solution. I have this one page that has like 12 queries going on, each pretty expensive, so I've opted to componentize them to localize and parallelize the queries. This also opens me up to use Suspense
around them, for nice loading states.
But with them so spread out, I'm finding myself passing searchParams
to each and every component. Some parts it goes 3-4 layers down, which imo looks really stupid, especially when there's already a solved solution client side.
And since url is considered to be the dynamic state of choice, I just wish there was some way to hook into it.What do you mean by "not a scalable solution"? What is the scale you are dealing with?
BTW: You can do parallel queries with
Promise.all()
, you don't have to move each query to an individual component for them to execute in parallel.Using client components doesn’t mean you’re giving up the cool things about the server. You can still pre-render the client components on the server, in fact, that’s what Next.js does (both client and server components are rendered on the server for the first render).
Also, you’re not giving up the loading states, if the operation is asynchronous you can use the “use()” API (React 19 tho) to unwrap a promise and it’ll continue to work just as fine, <Suspense> gets trigger
I’ve been there, I tried to make my whole app a server components app because it was the new shiny thing and it meant less JavaScript on the client, blah blah blah.
At the end the power of React lies on the Composition, you don’t need your whole app to be either Server Components or Client Components, composition lets you mix and match, however it’s convenient.
If there’s a solved and trusted solution in the client side then go for it, use the server for the data loading and prefetching, and the client for the stuff React has been doing for years
@showduhtung: Yeah I think you simply have a composition problem you are dealing with. I've been there too where you want to keep things all server components blah blah blah, but at the end of the day you just simply cannot without prop drilling, or creating a client component. I'm sure with enough home brewing you could come up with something... Id highly recommend changing your architecture of the features by utilizing client components as needed for search params.
Its easy to get stuck on forcing what you want with server comps and I get it.
Thats sucha a great take!