Next.js Discord

Discord Forum

(App dir) fetch server components based on some localStorage value?

Answered
Philippine Crocodile posted this in #help-forum
Open in Discord
Philippine CrocodileOP
Basically, I have an Arrivals component which takes some props about arrivals and displays them in a list, it all works great whenever the data is in the url. For instance:
/stop/321
would get the data from the stop 321 and everything works greatly
However, I would like to build a /favorites endpoint where I read from localStorage and get some stop ids to fetch from, here are my ideal solutions:

1. somehow get a "custom" server-rendered component and display a list without the client accessing the raw data.
2. fetch some JSON from the server and render the list myself using the Arrivals component as a client component and passing props to it.

Would server Actions help with 2.? I don't have much of a problem using api routes, I just find it non-ideal to include an entire client-side data fetching solution for this usecase.
Answered by Philippine Crocodile
Yeah I ended up doing this, its important the request goes through the server because of CORS issues.

In a /actions file
"use server";
async function fetchArrivalsAction(stopId: string) {
    return fetchArrivals(stopId);
  }

in a react client component
  const [arrivals, setArrivals] = React.useState<...| null>(null);

  React.useEffect(() => {
    void fetchArrivalsAction(stop.id).then((res) => setArrivals(res))
  }, [fetchArrivals, stop.id]);

Do take into account that it does not handle errors and its likely better to use Tanstack query or SWR.
View full answer

23 Replies

I am not sure I understand the entire question so I will try to answer with observations about your objective:
- the server can't read the localStorage, so yeah you need a client component that will read from the store then it will make a request to the server with the IDs
- this can be done with route handlers or server actions, it doesn't really matter and you don't need a data fetching library for this}

keep in mind that since the list of favorites is stored in the client they won't be synced for all devices and you can't server-render them. if you want any of this features you will need to store the favorites in the server
Philippine CrocodileOP
bump I guess
@Philippine Crocodile Could there be any way of storing the favorites as cookies? if not, how could server Actions help me?
yeah you could store it with cookies as well, then the server would be able to pre-render it. I am not sure server actions have any relation with what was discussed before
Philippine CrocodileOP
Yeah I ended up doing this, its important the request goes through the server because of CORS issues.

In a /actions file
"use server";
async function fetchArrivalsAction(stopId: string) {
    return fetchArrivals(stopId);
  }

in a react client component
  const [arrivals, setArrivals] = React.useState<...| null>(null);

  React.useEffect(() => {
    void fetchArrivalsAction(stop.id).then((res) => setArrivals(res))
  }, [fetchArrivals, stop.id]);

Do take into account that it does not handle errors and its likely better to use Tanstack query or SWR.
Answer
first you should indeed use cookies for local values that you want the server to be aware of
look for Safari ITP for rules of thumb about cookies
(1st party client-side cookie are limited to a week, 1st party http-only cookies are limited to a month, as far as I remember localStore is treated like a 1st party client-side cookie)
So you probably want an http-only cookie which is set via server call here
Then, I don't see the point of a server action to fetch data. Server actions are for actions: mutating data (create, update and such)
You could use a route handler + client-side fetch, that's a perfectly valid option that should not be dismisses just because new stuff exists, a basic "fetch" call or using Vercel SWR would do perfectly for basic use cases
The alernative would be to fetch server-side in your RSC, rely on a cookie and refresh the page when needed with a router.refresh
I feel like your current solution mixes a bit of both
If there is a server action somewhere, that would be to set the said HTTP-only cookie but I am not sure they can alter the response header (I fail to like server actions right now cause they abstract away the request/response too much which makes such use cases obscure)
@Eric Burel If there is a server action somewhere, that would be to set the said HTTP-only cookie but I am not sure they can alter the response header (I fail to like server actions right now cause they abstract away the request/response too much which makes such use cases obscure)
Philippine CrocodileOP
Yeah, I am aware that it does not seem optimal but I always found route handlers kind of akward, mainly due to the fact that I have to the endpoint manually which breaks with dev deployments
then I did not choose cookies because, if I understand correctly, they are just a long string and I am not sure how I'd store data of the shape of
{
name: string, 
id: string,
company: string
}[]
@Eric Burel in this case you encode the cookie as a string and decode it with JSON.stringify/JSON.parse
Philippine CrocodileOP
Yeah sounds pretty straightforward, I got scared because of expiration times and thought the character limit was kinda low
@Eric Burel not sure what you mean here? are you calling a route handler/API route during server render?
Philippine CrocodileOP
No, I mean from the client, doing a fetch requires absolute urls iirc
@Philippine Crocodile No, I mean from the client, doing a fetch requires absolute urls iirc
this is usually handled by having different environement variables, you can set default values in .env.development and .env.production namely