Call server action during render for table data
Unanswered
Tomistoma posted this in #help-forum
TomistomaOP
I'm rewriting a table component that supports column sorting (asc/desc). The original was fully server-side rendered and used a server action to fetch data. This worked okay with a mock API, but once hooked to the real one, the performance dropped, as calling the server action on every sort rerendered the page and became too slow. Caching isn’t viable due to data size and user volume.
I moved the table to a client component, which was easy, but now I’m stuck on data fetching. I created a wrapper around the table where tried passing a callback that calls a server action returning a promise, and then
I can’t move the fetch logic client-side because it needs access to secrets/env vars. I know I could use an API route instead, but I really dislike writing fetch logic, handling the errors, etc, and losing the simplicity of server action just being a simple function call, where it's all handled for you.
Is there any way to call a server action during render? Or a better pattern for client components getting data from the server-side data without constantly re-fetching?
I moved the table to a client component, which was easy, but now I’m stuck on data fetching. I created a wrapper around the table where tried passing a callback that calls a server action returning a promise, and then
use
-ing that promise in the component. But unfortunately I found out server actions can’t be called during render (why?).I can’t move the fetch logic client-side because it needs access to secrets/env vars. I know I could use an API route instead, but I really dislike writing fetch logic, handling the errors, etc, and losing the simplicity of server action just being a simple function call, where it's all handled for you.
Is there any way to call a server action during render? Or a better pattern for client components getting data from the server-side data without constantly re-fetching?
4 Replies
Asian black bear
Not answering your question, but you should know that server actions are not meant for data fetching. They are syntactic sugar for mutations. Fetching should be done in server components most of the time and if you render lists or tables then the correct use of key props will ensure that only the parts of the table that actually change will be rerendered.
TomistomaOP
Yeah, I'm aware they're not but they're also extremely convinient, and they make API routes feel old and clunky. The issue with a server component, and fetching the data in that server component is that if it rerenders then it will fetch the data again, and I don't know how to prevent that. The column headings are interactable, so they have to be a client component. I could potentially make the table rows a server component but that component would need to fetch the data but it would also rerender every time the client component changes one of the props and therefore would go and fetch the data agin.
Great Blue Heron
I also dealt with this issue and spent a few weeks in a battle with myself to start using API routes. In a recent app I built, I have a table that is in a client component with SWR fetching the data on load and revalidating when needed. It's worked great so far. If you want to keep your server actions, you could also just call the function in an API route. But like @Asian black bear , I would suggest moving it to a route instead.
@Great Blue Heron I also dealt with this issue and spent a few weeks in a battle with myself to start using API routes. In a recent app I built, I have a table that is in a client component with SWR fetching the data on load and revalidating when needed. It's worked great so far. If you want to keep your server actions, you could also just call the function in an API route. But like <@141252432054190080> , I would suggest moving it to a route instead.
TomistomaOP
hmm interesting, thanks for your input. Did you already have SWR installed when you switched to the API routes, or did you add SWR because you were going to need to fetch API routes on the client? The reason I ask is because part of the reason I liked the server actions is because it kept away the need for a library like SWR, which reduces client bundle size. Already by converting the table to client component (especially since mine renders markdown which adds a markdown parsing dependency), the client bundle size is going to increase and then adding SWR on top of it means extra weight. Of course, SWR isn't necessary, I'm just curious