Next.js Discord

Discord Forum

Client -> Server Data Submission Best Practise

Unanswered
American Sable posted this in #help-forum
Open in Discord
American SableOP
Trying to understand the logic with the app router here.

Use Case: Client clicks a button, which calls Server that triggers a server side action to create a user in the database, and then return data back to client

Historically, I'd have done an API route, some auth middleware logic if needed.

What's the best practise with the new app router and SSR. Should I still create this API route with middleware, or is there a better way to pass data to the server, without requiring an API route and middleware?

49 Replies

Asian black bear
The server actions are kind of a different contextualization of API routes
I am using Kinde for auth in my app and you can protect the server actions in the exact same way as an API route
American SableOP
but a server action can't be called from a client component can they?
so for getting data on page load and passing it down, thats fine, it can be done as a server action
but for client -> server
Asian black bear
I have only ever used server actions passed to client components as props
actually as I am looking through my project I ended up not even using them!
American SableOP
Ahh i've just found it, i didn't even realise you could do that
What I really dislike though is this awful nesting of components
I have a button component, that basically handles all my styles etc

export function Button({
  children,
  className,
  disabled,
  type = "primary",
  size = "default",
  fill,
  ...rest
}) 
and then in my UI i want to use that
      <Button
        onClick={async () => {
          onSubmit(true);
          await createUser();
          onSubmit(false);
        }}
      >
        {submit ? "Submitting" : "Create"}
      </Button>
but I can't use it like that, because that Page is SSR, so I now need to create ANOTHER button component, specifically for this page, which calls the master button component.....
unless im missing something
Asian black bear
So, I have found in the app dir that prop drilling is a total mess
At first I used a lot of context, but eventually found the library jotai which is basically perfect
You do not have to colocate components inside of the app directory structure if you don't want to, like you can totally import them for the lib dir for example
Then whatever RSC instantiates them can send the contextually relevant server action functions
American SableOP
Oh I know, but the issue here is that my Global button component is generic, and it just passes through the onClick function
so I need another CSR component for this route, for this button, to handle the logic of calling the server action from the client
Asian black bear
For a while I was thinking on simple routes to just have the page.ts file and another file alongside like client.ts to put whatever junk like that in
American SableOP
Oh no wait, i cant even do that
You're importing a component that needs useState. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.
Asian black bear
isn't your button use client?
American SableOP
So unless the entire nested route is totally static with no client interaction.....
Yep
but my parent Page is not
So my "dashboard" lets call it that is interactive
the whole thing needs to be CSR
Asian black bear
ohhhh haha yeah that is really confusing
American SableOP
at which point, given my whole app is interactive, i might as well just create 1 page route and slap use client on that
Asian black bear
nahhhh
there is a way to do it, just it is kind of subtle I think
okay check it out, you can import client components into server components
and you can pass server components through client ones but only as children
so if you want to make an interactive wrapper thing with an RSC inside, you have to instantiate it in a parent RSC and put the child RSC in there
like it is kind of weird, but it does actually work if you want like really light weight stuff in an accordion or something
as you are making a fully interactive app with less pressure on performance and web vitals using more client components is definitely the move, but remember that to get initial props like getServerSideProps you need to have RSC components. Otherwise it is create-react-app or gatsby with only client data fetching which does genuinely kind of suck
American SableOP
Mmmm i thought that's what I was doing
so page
import { createAccountButton } from "@/app/create-account-button";

export default function Home({ data }) {
  return (
    <main className="flex min-h-screen flex-col items-center justify-between p-24">
      <h1>Stripe Connect Demo</h1>
      <createAccountButton />
    </main>
  );
}
createAccountButton
"use client";
import { Button } from "@/components/button";
import { createUser } from "@/app/actions";
import { useState } from "react";

export function createAccountButton() {
  const [submit, onSubmit] = useState(false);

  return (
    <Button
      onClick={async () => {
        onSubmit(true);
        await createUser();
        onSubmit(false);
      }}
    >
      {submit ? "Submitting" : "Create"}
    </Button>
  );
}
oh, now it works.....
Asian black bear
hah yeah I was going to say that is perfect
American SableOP
literally didn't touch a thing lol
all i did was restart the dev process
Asian black bear
the next dev server is buggy af
waaaaaaay too much caching
sometimes I randomly restart it to establish dominance
people like me (complainers) used to say it was too slow, but it definitely isnt slow