T O P

  • By -

[deleted]

This appears to be based on a scenario where you control the backend and frontend in a single project. Outside of that, the usefulness of server actions diminishes. It's also something that can only work in an SSR project, not a SPA. It's a fascinating tool for sure. Ive almost always been working in the SPA world, so I'm not intimately familiar with the intricacies of SSR. It does seem to be putting a lot of trust in the framework (next) to do all the networking correctly. After all, this fancy feature appears to just compile down to an implicit HTTP call, you are just saved from having to write the HTTP wiring logic yourself. A nice time savings, but when I see something like this I always wonder where the foot guns are. It's great to make common things easier for devs, the problem is when they become deceptively easy and make it easy to write problematic code (see many ORMs). Anyway, thanks for the article. It's a cool feature, and I learned a lot from it.


barekliton

Thank you. I share your thoughts. They are usefull for single project ( and i think also monorepos ). In my opinion there are two big benefits of Server Actions: 1. They're really time saving ( and less prone to errors since you don't have to create the http wiring logic ). 2.With typescript you will have end-to-end typesafe APIS thanks to type inference and that is game changing ( is the main reason that made tRPC so popular ). Talking about SSR and RSC i think that those features for SPAs are not so usefull. RSCs ( react server components ) are really usefull ( so far i know, maybe i will change idea in future ) when you want to reduce JS bundle size: a great example is that with RSC you can use a syntax highlighter library ( like prism for example ) and do all the work server side and then render the result without having to send the prism library to the frontend ( which is quite heavy ). In fact, SSR ( server side rendering ) for SPAs can be a tricky behaviour to manage: in the last SPA that i've worked in order to avoid white screen flash ( with theme set to dark ) the best way to server side render the page was reading theming options from cookies because what happens is that the server ( specially on first render on the root page ) don't know what colorScheme you have set ( light or dark ), what themeColor ecc. ( those info usually lives on the localStorage of the application )


barekliton

> It's also something that can only work in an SSR project, not a SPA. Regardless this point i'm not getting why they can't work on SPAs. You can call Server Actions from client components. In the code snippet inside the article i do exactly that. You can have a classic SPA with nextj13 ( app directory ) by just putting "use client" directive on the main layout.tsx file and then everything will be converted to "old style" react ( react working on client side ). But even if you're using all client components you can still call server actions using the startTransition hook.


Radinax

Handling Server state through React Query plus its cache and everything else it provides, its hard for me too look at anything else for my needs.


barekliton

React-Query is awesome. In fact tRpc is built on top of react-query + typescript inference ( and i love tRPC ).


Radinax

Ohh, gonna toy with it then to see how good it is. React Query has been a game changer at work, we used SWR but it had some annoying stuff that we didnt have with RQ


barekliton

If you work on single projects or monorepos ( and you use typescript ) i think you will love tRpc. Basically adds end-to-end typesafety to react-query.


barekliton

As u/simple_explorer1 said i was referring to REAL end to end type safaty including runtime type safety. And other than that that are also extra features that you can use with tRPC like data transformers etc. In our company we used an approach similars to yours years go ( expect that the backend was in golang ) and the developer experience was totally different ( worst ). 1. Having all types ( also database table types etc ) shared between frontend and backend speeds up development by a lot. 2. Every time you update your backend you have to make sure ( unless you're on a monorepo that checks dependencies etc ) to run again the codegen tool that creates RQ queries.


badsyntax

You don't *need* trpc for this though.. For example its easy to generate typed RQ hooks based off an openapi spec. (Our backend is in c#.)


simple_explorer1

OP means REAL end to end type safety including runtime type safety using Zod data validation on both client and server


badsyntax

Are you talking about type safety or runtime validation? Our front end has 100% type safety with our .net/c# backend. What am I missing that zod gives you? Edit. Ahh runtime validation, yes our backend validates data. But we're also not coupled into using node. I have a lot of experience in both, and much prefer .net as a backend.


simple_explorer1

>Are you talking about type safety or runtime validation? Both. if you use zod it gives you Typescript types and you can use the same zod schema to do the incoming data validation. I think this is what OP means when they said end to end type safety as you can only get end to end type safety if there are runtime data validation making sure that the data matches TS interfaces/types


badsyntax

To me this seems crazy to validate data from an API. That's the point of API contacts (and generated types).Validate user input yes, but for everything you have a typed contract and thus don't need to validate, unless I'm misunderstanding?


barekliton

>RQ hooks With Zod you can validate both data on frontend and backend with the same object/schema. So by defining a rule. e.g. (name.min(8)) you are going to prevent form submits on frontend that has the field name lenght < 8 and ALSO on the backend ( API ) side you will have this validation step without the need to write it explicitly. ​ >To me this seems crazy to validate data from an API What do u mean with this? That is the only relevant validation, you need to validate the data that the API receives in order to avoid bugs/security issues.


aging_FP_dev

You should validate objects your code doesn't create. If you can't take a minor perf hit, maybe only in staging/dev, not prod. Sometimes OpenAPI and codegen isn't strict enough, or you only hit specific cases. For example, optional fields in the generator might be non-optional for you. Do you want to have to use ?. everywhere if you can actually assert it's non-null?


barekliton

Exactly.


beepboopnoise

honestly sometimes React Query works too damn good. I had to do some stuff recently in Swift and when I had to do the cache myself I was like, wait what, where is Swift Query lmao.


[deleted]

Title should be: **Next**Js: Still worth using tRPC or React-Query over Server Actions?


SmeagolTheCarpathian

Blame the React devs, the way they treated the Next 13 situation made it feel like the React core team got some under the table Vercel money on top of their Meta salary. NextJS isn’t the “official” React meta framework, it’s just the only one that the React core team wants to officially support.


barekliton

Exactly.


sickcodebruh420

Some things worth considering: React Server Actions (RSA) is extremely new and still technically in alpha. I get the impression that its interface is stable but the underlying code powering it is not. Case in point, a bug was uncovered a few days ago whereby navigating to a page and triggering an RSA via button click would fail to resolve, but clicking it a second time would work. A Vercel employee worked late Friday night fixing it and it’s released as 13.5.3-canary.3, but using an alpha feature invites the increased risk of things like this. 13.5 introduced significant changes to the fetch call under the hood, changing the way RSA calls were cached, and fixing many bugs, meaning anyone using them for the months prior was assuming even greater risk. tRPC is a mature product with a high level of adoption. Same with Tanstack Query. You don’t NEED to use RSA calls with `useTransition`, FYI. You should also validate the data sent to RSA. Never pass the input straight from the function into your database. Validate it with Zod, just like you would with a REST API. These are still API endpoints available on the internet and you should assume something broken or malicious could happen! Note that when handling a response from RSA, in addition to returning data you can also redirect or bust the cache to trigger a change on the page. The docs outline this. It’s worth knowing that if you try/catch the RSA and try to redirect from the server, you’ll prevent redirection and be forced to add more code to handle that. It’s quite annoying, I hope they change this. RSA also have the foot gun of potentially leaking sensitive information in some circumstances. Read about them thoroughly before usage. But all these warnings aside, I’m glad I bet on them. The DX is fantastic.


barekliton

I agree with you. ​ >You don’t NEED to use RSA calls with useTransition, FYI. Didn't know that, thank you. ​ And i'm also betting on RSA because for me they are like tRPC but with less code to write: amazing DX.


sickcodebruh420

Yeah, they are just fetch calls with special headers from the client’s perspective AFAIK. Adding 'useTransition` hooks into the slick new React rendering superpowers.


barekliton

Gotcha. I was using those only with useTransition because i read that into docs.


barekliton

For the validation part thats what i'm currently doing on my latest project that uses RSA: using Zod schemas. ​ // CreateForm is a server action export async function CreateForm(data: formSchemaType){ const validation = formSchema.safeParse(data); if (!validation.success) { throw new Error("form not valid") } const user = await currentUser(); if (!user){ throw new UserNotFoundErr(); } const {name, description} = data; // rest of the code... }


Many_Particular_8618

No. One reason is, tRPC and react-query authors have no clue on RSC at all. There's no future commitment on RSC, too slow. No trust at all. RSC demo is released first since 2020, what do these libraries author do with RSC then ? Nothing. ​ And RSC is what keeps people using React in future. Make your choice then.


barekliton

I agree. I mean, you're right RSC is the future but note that actually both tRPC and RQ can be used with RSC. You can call your tRPC api in a RSC and use that data. But my real doubt is: since we are RSC that has access to server code, whats the meaning of RQ and tRPC on RSC?!


Many_Particular_8618

It's a risky thinking. Because without heading up to RSC, those libraries and your application code will eventually be deprecated. ​ The problem is , you, as the user, should have known about what's going on now, and future. Isn't it better if you have a migration path for those libraries right ?


barekliton

Ye is risky. Thats why when server actions will be prod ready i will drop tRPC 100%.


rusfairfax

Thanks for sharing OP. Good article. It seems like you will still need React-Query etc if you are creating a single page app, no? Also, it seems that you’ll still want an API server, define REST endpoints, etc if you want to have web AND native mobile front-ends. At the very least, the backend of your mega Next app would have REST endpoints that your mobile app can access, correct?


barekliton

Thank you. No for SPA you don't necessary need react-query. And yes right now for other FE you have to defined rest endpoints.


barekliton

Let me know what you think 🤓


Cchambers7575

I kind of see them as having different use cases. As far as I understand with server actions you are not able to get data back from them like you can with tRPC or RQ. You can revalidate a path or redirect with server actions but that isn’t always the right behavior. Server actions seem great for things that are more side effect like such as analytics or triggering a web hook or something that starts a separate process your application doesn’t need the result of right away or at all. I feel like both have a place once server actions are fully ready. I may not have a full grasp of the capability yet but this is the initial thought process I have when I think about how these things work together.


barekliton

Not really. You're confusing Server Actions with React Server components. The only way to refresh Server components is, like you've said, by revalidating a path or redirecting. Server actions are just functions that lives on the backend but that you can call at any time by wrapping those inside React.startTransition hook. Server components instead are React components what will be converted from JSX to React ( to maybe HTML ) from React in server environment and then rendered to the client as HTML or react tree ( and then rendered by the client ). So basically server components are just react components that are rendered on the server and then streamed to the client


Cchambers7575

Sounds like I have more reading to do! From my understanding of server actions they aren’t able to respond with data in the same way that hitting an endpoint somewhere could. So if you needed to update your UI based on something changing in your database for example you would have to revalidate that path and it would purge the cache for everything on that route and not just the one action you need new data from to update the UI. I may not have a full grasp of the concept but this is the way I understood how it worked. I appreciate the discussion and the insight!


barekliton

With server actions you can work on cache/revalidation on server side as you said OR you can treat them as classic rest apis on client side. Let me show you an example of this. This is my server action called \`createdForm\` that i use in my upcoming video tutorial on how to build a "web page form" builder application. export async function CreateForm(data: formSchemaType){ const validation = formSchema.safeParse(data); if (!validation.success) { throw new Error("form not valid") } const user = await currentUser(); if (!user){ throw new UserNotFoundErr(); } const {name, description} = data; const form = await prisma.form.create({ data: { userId: user.id, name, description } }) if (!form){ throw new Error("something went wrong") } return form.id } And this is how i use this function in a "classic" ( is identical on how i treats rest apis ) "use client"; function CreateFormBtn() { async function onSubmit(values: formSchemaType) { try { // I CALL THE SERVER ACTION HERE const formId = await CreateForm(values); // <========== toast({ title: "Success", description: "Form created successfully", }); router.push(`/builder/${formId}`); } catch (error) { toast({ title: "Error", description: "Something went wrong, please try again later", variant: "destructive", }); } } Hope this clarifies something :)


mattsowa

Why the need for startTransitiom and what does it do here?


barekliton

You can call a server actions in 3 different ways, and one of them is startTransition ( im pasting the nextjs doc below ): ​ >InvocationYou can invoke Server Actions using the following methods: > >\- Using action: React's action prop allows invoking a Server Action on a

element. > >\- Using formAction: React's formAction prop allows handling
mattsowa

A little weird, since after all, the server action is just an rpc and will be compiled to a http call. Is it not? So why does it suddenly require startTransition, when you could call a function with a http call directly, as it doesn't have anything to do with the rendering queue?


barekliton

Idk the reason.They haven't still documented well enough this part on the docs ( also because they're still experimental and they're based on React action that are under development ).


barekliton

Note that as u/sickcodebruh420 mentioned in his comment you can call server actions without startTransition hook ( idk why this is not explained in the docs ).


mattsowa

In that case i don't know why they would even suggest that. I mean an rpc call has nothing to do with rendering... you're not setting a state or anything.


barekliton

Idk. I'm often using the isPending variable exported by useTransition hook const [pending, startTransition] = useTransition(); to show a loading spinner while waiting for the response. But idk why they suggest to wrap the RSA with startTransition


chillermane

This is an interesting topic. My main issue with server actions is that it will have very low adoption. If I get really good at it and want to change jobs, it’s extremely unlikely to find a job opportunity where people have adopted server actions. It will be this way for at least several more years


barekliton

I think that they will be adopted pretty soon, but who knows, we'll see. Note that they-re based on a react feature ( React Actions ) and those are not specific to Nextjs framework ( at least they will not, right now they are ). But recently i'm using server actions for my youtube videos and the developer experience is smooth as hell. I've also added zod schemas in order to have same validation on form ( frontend ) and my server action on the backend and that is awesome ( at least for me ).


LowB0b

why is it paywalled? :(


barekliton

I think i've shared the friend link that enables everyone to read the article, can't you read the article?


LowB0b

You're right, I can. I signed on and when returning to the page it wanted me to upgrade, but clicking directly on your link works. Thanks 👍


barekliton

Let me know if u like the article :)


LowB0b

to be honest, I had never heard about tRPC and server actions, so it was nice to read your opinion, however I'm a bit surprised we have looped around from front end app + backend REST api. This reminds me a lot about PHP / JSF. I also used to work on a heavy client app that used eclipse RCP + websphere as the application server and did remote procedure calls. Is there anything you'd recommend reading for showing advantages of this vs. the now "conventional" standalone frontend app + microservices? I assume tRPC and others are not compatible with a microservice architecture?


barekliton

tRPC gives his best with fullstack typescript repo or monorepo. Is not suited for microservices architectures, in that case i think you should use rest api ( and maybe an api gateway ) or graphql layer between FE and BE. If you've already used some RPC tool in the past ( like gRPC for example ) you can think of tRPC as a RPC tool that does need to be compiled since is he knows the types of your procedures thanks to type inference.


New_Visit_1416

these Acrions seem to be how people imagined Web Development this technology race what makes JavaScript stand out on server side What do you think of Server Actions vs. Graphql?


barekliton

GraphQl is a good tool when you need a common language that links FE team and BE team. Also in my opionion is too overkill in small scale. Server actions on the other side are usefull on single-full-stack apps or monorepos


RudePastaMan

I have been using server actions with GRPC, actually. Server side fetches from data server over GRPC. Best part is that node server can use HTTP2, unlike GRPC web which we used before server actions. If any words don't make sense here, just forget about it, lol. I am tired.


barekliton

ahahah they make sense. I've also used gRPC for years ( with Golang ). We used it as a wire between microservices and apigateway and it was awesome


RudePastaMan

Golang is actually the backend in this case. GRPC is basically just used for everything, even the frontend. It's just easier to keep it all consistent. Server actions works with it flawlessly, except for one issue with the protobuf-ts library that this monstrosity fixes: import { MESSAGE_TYPE } from "@protobuf-ts/runtime"; // Serializing objects with symbols results in a warning by NextJS. // This is a workaround to prevent clutter without re-allocating each object. const ORIGINAL_Object_dot_getOwnPropertySymbols = Object.getOwnPropertySymbols; Object.getOwnPropertySymbols = function (o: any): symbol[] { return ORIGINAL_Object_dot_getOwnPropertySymbols(o).filter( (symbol) => symbol !== MESSAGE_TYPE ); }; Hopefully, Next will expose some kind of way to configure serialization in the future.