Fetching data in a layout based on search params
Unanswered
Brown bear posted this in #help-forum
Brown bearOP
I have a layout that needs to fetch data from an API — the request depends on URL query params (used for filtering).
Since RSC layouts don't have access to
But does that really mean I need to create an Route Handler, then call it from the client component with something like
It feels like a lot of ceremony — and wasteful, since the initial SSR render would be calling into itself over the internet.
Has anybody got a better pattern for this?
Since RSC layouts don't have access to
searchParams, I understand they need to be client components if they’re to respond to URL changes.But does that really mean I need to create an Route Handler, then call it from the client component with something like
use(fetchApiRouteHandler())?It feels like a lot of ceremony — and wasteful, since the initial SSR render would be calling into itself over the internet.
Has anybody got a better pattern for this?
49 Replies
@Brown bear I have a layout that needs to fetch data from an API — the request depends on URL query params (used for filtering).
Since RSC layouts don't have access to `searchParams`, I understand they need to be client components if they’re to respond to URL changes.
But does that really mean I need to create an Route Handler, then call it from the client component with something like `use(fetchApiRouteHandler())`?
It feels like a lot of ceremony — and wasteful, since the initial SSR render would be calling into itself over the internet.
Has anybody got a better pattern for this?
>I have a layout that needs to fetch data from an API
better to not fetch any data into a layout.tsx
>I understand they need to be client components if they’re to respond to URL changes.
you can still put stuff in layout without making client component.
you dont need to create a route handler just to fetch in layout.
i still does a bit of ceremoney in the file structure ways but you can make use of parallel routes to create "slots" in your layout.tsx in which you can then retrieve searchParams on parallel page.tsx which resides in your layout.
alternatively you can just put the layout in your leaf pages.
better to not fetch any data into a layout.tsx
>I understand they need to be client components if they’re to respond to URL changes.
you can still put stuff in layout without making client component.
you dont need to create a route handler just to fetch in layout.
i still does a bit of ceremoney in the file structure ways but you can make use of parallel routes to create "slots" in your layout.tsx in which you can then retrieve searchParams on parallel page.tsx which resides in your layout.
alternatively you can just put the layout in your leaf pages.
Brown bearOP
Oh interesting. I definitely don't want to render the layout in each leaf page as I'd lose state when navigating
but I'll check out parallel routes
I guess I'd need a catch-all parallel route and have that render next to it? Would that then be refreshed upon navigation between sub-routes?
this is how vercel demonstrated how they made the navbar in the vercel site
iirc no. i forgot the exact implementation but you can try using between catch all and
default.tsxBrown bearOP
Ok, I got it working with with a catch-all as
That's wildly complex.
I don't see why Next.js doesn't let you define a
default.js doesn't revalidate on navigation..
├── @foo
│ └── [...catch-all]
│ └── page.tsx <-- this'll revlaidate when navigating between /customers and /invoices
├── customers
│ └── page.tsx
├── invoices
│ └── page.tsx
├── layout.tsx
└── page.tsxThat's wildly complex.
I don't see why Next.js doesn't let you define a
shouldRevalidate function on a layout, smiliar to Remix 🤔because again, next's layout is different from remix's.
next's layout acts as a shell that fundamentally stays if route segment doesn't change.
accessing stuff like /invoices doesn't "flatten" your UI from layout to page but are meant to be compatible to partial rendering.
next's layout acts as a shell that fundamentally stays if route segment doesn't change.
accessing stuff like /invoices doesn't "flatten" your UI from layout to page but are meant to be compatible to partial rendering.
it isn't technically feasible since in nextjs we have a lot of partial rendering in order to optimize speed/ui/bundle size.
one example being the ability to only re-render subpages keeping the layout the same instead of re-rendering the whole layout-page tree.
you can always build the shouldRevalidate function if you make your own page wrapper.
you dont have to use layout.tsx :)
you dont have to use layout.tsx :)
Brown bearOP
I've not had first-hand experience of the benefit of partial pre-rendering yet — obv comes at a cost, but seems pretty cool.
Thanks for your support 👍
Thanks for your support 👍
no not partial pre-rendering, just partial rendering which has been here since next 13
Brown bearOP
Oh, just partial rendering. Not sure I see how partial rendering makes
shouldRevalidate technically infeasible — it's exactly what Remix does with shouldRevalidate — by default all routes (layouts and pages) revalidate, but you can opt-out with shouldRevalidate 🤔@Brown bear Oh, just partial rendering. Not sure I see how partial rendering makes `shouldRevalidate` technically infeasible — it's exactly what Remix does with shouldRevalidate — by default all routes (layouts and pages) revalidate, but you can opt-out with shouldRevalidate 🤔
because for example if you navigate from
/shop/a to /shop/b, /shop/layout.tsx doesn't get rerendered. And when you do <Link href="/shop/b"> from /shop/a, they also do prefetch of the RSC from /shop/b/page.tsx only.next's by default do soft navigation where only the children of a page is swapped if the parent route segment stays the same
Brown bearOP
yeah, so why couldn't there be a shouldRevalidate (or shouldUpdate/shouldRerender) fn which allows you to tell next.js that the layout should re-render
next's by default do soft navigation where only the children of a page is swapped if the parent route segment stays the sameyeah, that's what remix v2 used to do — they changed the default in React Router v7 to default to always revalidate, but you can still configure it as you wish
because the definition of layouts here in nextjs and remix are different...
Brown bearOP
yeah, I'm trying to understand the next.js concept of a layout — they feel quite limiting initially — having to punch lots of little holes in them with parallel route slots to make them reactive to URL changes feels unusual.
I'm sure there's good reason for it — I just don't see it yet.
I'm sure there's good reason for it — I just don't see it yet.
its just the new mental model of RSC
Brown bearOP
I don't think it's an RSC thing? It's a next.js thing. — the RSC payload can be fetched for any routes in theory?
i.e. the same response that you get when you soft navigate from
/ to /shop/ayou're right, i might have engrained this model too too deep into nextjs. what i meant is about what the concept of how they envisioned RSC to be at the time before. at that time, only nextjs uses it so thats where i picked it up
back again you dont have to and can still implement remix-style page wrapper on page.tsx it would still be as performant (if not easier in the eyes)
@Brown bear yeah, so why couldn't there be a shouldRevalidate (or shouldUpdate/shouldRerender) fn which allows you to tell next.js that the layout should re-render
might have to ask the github discussion for this if you're talking about navigations like <Link>
@alfonsüs ardani back again you dont have to and can still implement remix-style page wrapper on page.tsx it would still be as performant (if not easier in the eyes)
Brown bearOP
This is interesting — how would you envisage that working? Would you effectively do routing in the page component?
no, just put the layout and the breadcrumb in the page.jsx but you know, make a wrapper so it wont be repetitive
Brown bearOP
oh, but then it's not a layout with persistent state across navigations?
kinda becomes Page Router
you put persistent state stuff in layout.tsx
but then breacrumb doesn't have persistent state doesn't it?
but then breacrumb doesn't have persistent state doesn't it?
Brown bearOP
Layouts often have persistent state — nav open / closed for example
and they also sometimes fetch data based on query params (filters etc.)
which are the two things I'm keen on
interesting
nav open and closed can be done in client components (which you can safely add in layout.tsx), but if ure saving state via query params, then you can still wrap it in page comonent and read query params from there or just use parallel routes
if the state of the nav is saved based on query params then it basically can also be accessed in the page.tsx. so if its in query params then it is persisted even if you implemented it in page.tsx
Brown bearOP
wrapping page with a pretend layout also makes transitions (animations) impossible
hmmm have you tried it? the browser have pretty good skill at comparing 2 divs and animating between the two, especially with ViewTransition
Brown bearOP
I think parallel routes seem to be the answer — it does achieve what I want, it's just quite complex
@alfonsüs ardani hmmm have you tried it? the browser have pretty good skill at comparing 2 divs and animating between the two, especially with ViewTransition
Brown bearOP
yeah to be fair I'm thinking about pre-view transition API animations
the new view transition API is pretty incredible tbh
like motion.div?
Brown bearOP
yeah, motion or just CSS transitions with TransitionGroup etc.
where you need the component that manages the transition to persist
@Brown bear where you need the component that manages the transition to persist
layout.tsx is just a dumb file man i have nothing left to say lol. do they have server-client interleaving in Remix?
@alfonsüs ardani layout.tsx is just a dumb file man i have nothing left to say lol. do they have server-client interleaving in Remix?
Brown bearOP
I've not looked at their RSC impl. yet — I'd be suprised if you can't revalidate a layout on navigation though
allright! good luck!