Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Issue #236]: Server action example #341

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

rylew1
Copy link
Contributor

@rylew1 rylew1 commented May 29, 2024

Ticket

Resolves #236

Changes

  • add a server action example

Context for reviewers

  • Chose the useFormState method (instead of just assigning the server action function to the action attribute of the form) . I believe this is a little more clear to handle returned data and possibly validation errors

  • I did not tie into an actual API call - though we could add as a follow on maybe (as described here Add example API request approach #116)

  • Believe we could use useOptimistic in the example to show, for example, show optimisticName immediately, then a serverActionReturnedName when the server action completes

  • the example uses native form instead of USWDS <Form>. The USWDS <Form> requires an onSubmit handler

  • For loading you might be able to tie in useFormStatus / pending state

Screen.Recording.2024-05-29.at.4.56.46.PM.mov

@rylew1 rylew1 requested review from sawyerh, lorenyu and acouch May 29, 2024 23:54
Copy link

github-actions bot commented May 29, 2024

Coverage report for app

St.
Category Percentage Covered / Total
🟢 Statements 93.1% 81/87
🟢 Branches 82.35% 14/17
🟢 Functions 93.33% 14/15
🟢 Lines 93.59% 73/78

Test suite run success

16 tests passing in 5 suites.

Report generated by 🧪jest coverage report action from 7eeaf44

@rylew1 rylew1 requested a review from jcq May 30, 2024 00:12
@rylew1 rylew1 added this to the Next.js App Router milestone May 30, 2024
@rylew1 rylew1 requested review from a team and removed request for sawyerh, lorenyu, acouch and jcq May 30, 2024 17:54
app/src/app/[locale]/serverAction/page.tsx Outdated Show resolved Hide resolved
app/src/app/[locale]/serverAction/page.tsx Outdated Show resolved Hide resolved
app/src/app/[locale]/serverAction/page.tsx Outdated Show resolved Hide resolved
app/src/app/[locale]/serverAction/page.tsx Outdated Show resolved Hide resolved
app/src/app/[locale]/serverAction/page.tsx Show resolved Hide resolved
@@ -0,0 +1,84 @@
"use client";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there alternative approaches where the entire page doesn't need opted out of being a server component?

Copy link
Contributor Author

@rylew1 rylew1 May 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No expert at this, but I believe you can have server only forms - but then you can't demo the client hooks like useFormStatus and useFormState (not that these hooks have to be used with a server action). For a server-based form, instead of useFormState you would just call the server action function directly in the form's action attribute - but you can't do any user input in textboxes and such.

I'm not sure if another server (second) example makes sense for comparison? IE - Just call a server action from a server component page - and pass the resulting data down into a client component that displays it.

Just wanted to get things started on this cause I think it would have helped on our project if we had these examples.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think one alternative is to have a separate component for the part that depends on the client-only hook. I think for most forms it's likely just the submit button, so it might be something like:

// components/SubmitButton.tsx
"use client";

function SubmitButton(props) {
  const { pending } = useFormStatus();

  return <button disabled={pending} type="submit">{props.label}</button>;
}

I think that would then allow the page to be a server component with a small client-side island.

Copy link
Contributor Author

@rylew1 rylew1 May 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sawyerh this makes sense and we can try this - but we won't be able to demo useFormState without making the form (and text inputs) client components. I updated it to use a page but with a client form component with useFormState .

It can work with the form in a server component (with some eslint rules turned off (no-misused-promise). Lmk if we want multiple examples or something.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be helpful for the example to also demonstrate how to test the page, as well as render it in Storybook.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can give tests and storybook a shot when we decide on how we want to construct these example(s)

@rylew1 rylew1 requested a review from sawyerh May 31, 2024 01:34
@rylew1
Copy link
Contributor Author

rylew1 commented Jun 24, 2024

Also should this be in the nav? Not sure if in general we want the nav to just dynamically include all routes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Demonstrate a form and server action
2 participants