Next.js Discord

Discord Forum

Can Route Handlers return RSCs?

Unanswered
Yacare Caiman posted this in #help-forum
Open in Discord
Yacare CaimanOP
I am looking for a way to fetch RSCs from the client in order to implement infinite scroll. In particular, I want all of the benefits of RSCs like the React Cache and Fetch Cache, as well as streaming support via Suspense boundaries.

Server Actions almost work for this case, but they no longer seem to be recommended for data fetching (only for mutation) and they also don't leverage the React Cache, which is critical for deduping requests.

37 Replies

You can archive this, by fetching the „first load“ serverside and pass it down to a clientcomponent, that contains for example a button with „load more“. Inside this client component I would call an api from your server (route handler) that returns the new data. In this case you have the cache, the serverside execution and the result works (save the new data in an array and render it) @Yacare Caiman
@Yacare Caiman Can you be specific about what is being returned from the Route Handler? My question is about returning RSCs, not JSON data.
yea, you can't return RSC from your server action. But you can return data. And then work with the data
Yacare CaimanOP
It's frustrating because you can actually return RSCs from server actions, and they do mostly work (even Suspense boundaries stream in). But there are little issues like the React Cache not deduping requests.
oh ok, never heard about it
Yacare CaimanOP
Hopefully this changes in the future -- it feels very natural to want to re-use the RSCs I created for the "first load" in subsequent rows of the infinite scroll, rather than creating an entirely new data-fetching/rendering pattern for them
yea, that's kinda hard.. maybe the thing with the route handler is something for you, because you can reuse the fetching methods, that you used for the rsc...
@Yacare Caiman "but they no longer seem to be recommended for data fetching" > any source on that?
I was surprised by this use case too, it's true that since they use a POST method they are not the most usual approach, but for instance GraphQL uses POST and it's not a problem
they have less caching capabilities maybe
anyway I think we would need to know more about your use case to answer, there are perhaps alternative patterns like // routes or intercept routes, that allow to display a page within another page basically
@Yacare Caiman It's frustrating because you _can_ actually return RSCs from server actions, and they do mostly work (even Suspense boundaries stream in). But there are little issues like the React Cache not deduping requests.
You mean if the server action renders a component like <Parent><Child /></Parent> if parent and child get the same data, "cache" won't dedup?
this sounds like a bug more than a limitation of server actions
but that could make sense, under the hood "cache" is setup in Next.js render process for the current request and server actions are probably outside of this process
I'm using server action for infinity scroll in one of my project which return a cached result from unstable_cache
so far so good, the only problem is when doing revalidateTag or revalidatePath the scroll will jump😵
@Ray I'm using server action for infinity scroll in one of my project which return a cached result from `unstable_cache`
just a thing to be careful of when switching from "cache" to "unstable_cache" is that "unstable" is shared across requests
so you need to make sure you use the right inputs to not leak data
while React cache is scoped to the current request
@Eric Burel just a thing to be careful of when switching from "cache" to "unstable_cache" is that "unstable" is shared across requests
yeah I know, that's why I need to use revalidateTag after some mutation
@Ray yeah I know, that's why I need to use `revalidateTag` after some mutation
what's the relation with revalidateTag?
you mean to be able to reset this cache with new values I guess
I was meaning more that if you have a dynamic security check like checking the current user, you can't do that in the function wrapped by unstable_cache
because the risk is to cache the response for the first authenticated user
and serve it to other users
it can't detect dynamic functions like cookies() being called within the function, you have to pass the right user id as argument (as they do in the doc), this can trip up people sometimes
yea, nothing related for authentication in my case
yeah makes sense
here is the problem
@Ray here is the problem
ah yeah I see
let's hope these use cases are better supported in the future, Server Actions are kind of a first step to allow serving RSCs directly without having to create an actual page
for know I feel like we are stuck to getting data server-side but then render using a client component and updating using data
Yacare CaimanOP
@Eric Burel sources for my comment on using server actions for fetching no longer being recommended:
- https://github.com/vercel/next.js/commit/29fcd57ed1a5566fc00599be53732b187d17925f
- https://react.dev/reference/react/use-server#caveats (check the last one)

Maybe the core reason is due to the fact that Server Actions are run sequentially?
You mean if the server action renders a component like <Parent><Child /></Parent> if parent and child get the same data, "cache" won't dedup?

@Eric Burel - yes, exactly. Would love to hear that it's a bug, but given the above, I worry it's not intended to work.
@Ray - thanks for sharing your experience, and I'm glad to hear that unstable_cache works as an alternative. Definitely a bummer regarding the scroll position, since otherwise you are very close.
for know I feel like we are stuck to getting data server-side but then render using a client component and updating using data

For a complex card (i.e. composed of multiple data fetches), it's quite a lot to write to give the same result as what we can get for free on the server with Suspense. But I agree with your assessment.