#Client -> Server Data Submission Best Practise

50 messages · Page 1 of 1 (latest)

robust dirge
#

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?

plucky grottoBOT
#

🔎 This post has been indexed in our web forum and will be seen by search engines so other users can find it outside Discord

🕵️ Your user profile is private by default and won't be visible to users outside Discord, if you want to be visible in the web forum you can add the "Public Profile" role in id:customize

✅ You can mark a message as the answer for your post with Right click -> Apps -> Mark Solution
(if you don't see the option, try refreshing Discord with Ctrl + R)

glass holly
#

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

robust dirge
#

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

glass holly
#

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!

robust dirge
#

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

glass holly
#

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

robust dirge
#

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

glass holly
#

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

robust dirge
#

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.

glass holly
#

isn't your button use client?

robust dirge
#

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

glass holly
#

ohhhh haha yeah that is really confusing

robust dirge
#

at which point, given my whole app is interactive, i might as well just create 1 page route and slap use client on that

glass holly
#

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

robust dirge
#

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.....

glass holly
#

hah yeah I was going to say that is perfect

robust dirge
#

literally didn't touch a thing lol

#

all i did was restart the dev process

glass holly
#

the next dev server is buggy af

#

waaaaaaay too much caching

#

sometimes I randomly restart it to establish dominance