-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #30 from IdoPesok/use-form-state-docs
added docs for useFormState hook to address #29
- Loading branch information
Showing
5 changed files
with
161 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 18 additions & 0 deletions
18
examples/showcase/content/examples/use-form-state/actions.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
"use server" | ||
|
||
import z from "zod" | ||
import { createServerAction } from "zsa" | ||
|
||
export const produceNewMessage = createServerAction() | ||
.input( | ||
z.object({ | ||
name: z.string(), | ||
}), | ||
{ | ||
type: "formData", | ||
} | ||
) | ||
.handler(async ({ input }) => { | ||
await new Promise((resolve) => setTimeout(resolve, 500)) | ||
return "Hello, " + input.name | ||
}) |
44 changes: 44 additions & 0 deletions
44
examples/showcase/content/examples/use-form-state/use-form-state-example.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
"use client" | ||
|
||
import { Button } from "@/components/ui/button" | ||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" | ||
import { Input } from "@/components/ui/input" | ||
import { useFormState } from "react-dom" | ||
import { toast } from "sonner" | ||
import { produceNewMessage } from "./actions" | ||
|
||
export default function UseFormStateExample() { | ||
let [messages, submitAction] = useFormState( | ||
async (previousState: string[], formData: FormData) => { | ||
const [data, err] = await produceNewMessage(formData) | ||
|
||
if (err) { | ||
toast.error("Error!!!") | ||
return previousState | ||
} | ||
|
||
return [...previousState, data] | ||
}, | ||
["my initial message"] | ||
) | ||
|
||
return ( | ||
<Card className="not-prose"> | ||
<CardHeader> | ||
<CardTitle>Use Form State</CardTitle> | ||
</CardHeader> | ||
<CardContent className="flex flex-col gap-4"> | ||
<form action={submitAction} className="flex flex-col gap-4"> | ||
<Input name="name" placeholder="Enter your name..." /> | ||
<Button>Create message</Button> | ||
</form> | ||
<h1>Messages:</h1> | ||
<div> | ||
{messages.map((message, index) => ( | ||
<div key={index}>{message}</div> | ||
))} | ||
</div> | ||
</CardContent> | ||
</Card> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
--- | ||
title: "useFormState" | ||
group: "Client Side Querying" | ||
groupOrder: -10 | ||
--- | ||
|
||
# useFormState | ||
|
||
<Warning> | ||
useFormState has been **renamed to useActionState** in newer versions of | ||
React. The gist of these docs is the same, but the API has changed slightly. | ||
</Warning> | ||
|
||
### Server Code | ||
|
||
When defining your action on the server, be sure to set the `type` to `"formData"` to indicate that the input is a `FormData` object. | ||
|
||
```typescript:actions.ts | ||
"use server" <|highlight|> | ||
|
||
import z from "zod" | ||
import { createServerAction } from "zsa" | ||
|
||
export const produceNewMessage = createServerAction() | ||
.input( | ||
z.object({ | ||
name: z.string(), | ||
}), | ||
{ | ||
type: "formData", <|highlight|> | ||
} | ||
) | ||
.handler(async ({ input }) => { | ||
await new Promise((resolve) => setTimeout(resolve, 500)) | ||
return "Hello, " + input.name | ||
}) | ||
``` | ||
|
||
### Client Code | ||
|
||
On the client, you can use `useFormState` to manage the state of your form. This hook takes two arguments: a function that will be called with the previous state and the form data, and an array of initial values. | ||
In return, you will get a variable holding the current state and a function to submit the form. | ||
|
||
```typescript:my-client-component.tsx | ||
"use client" <|highlight|> | ||
|
||
import { Button } from "@/components/ui/button" | ||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" | ||
import { Input } from "@/components/ui/input" | ||
import { useFormState } from "react-dom" <|highlight|> | ||
import { toast } from "sonner" | ||
import { produceNewMessage } from "./actions" | ||
|
||
export default function UseFormStateExample() { | ||
let [messages, submitAction] = useFormState( <|highlight|> | ||
async (previousState: string[], formData: FormData) => { <|highlight|> | ||
const [data, err] = await produceNewMessage(formData) <|highlight|> | ||
<|highlight|> | ||
if (err) { <|highlight|> | ||
toast.error("Error!!!") <|highlight|> | ||
return previousState <|highlight|> | ||
} <|highlight|> | ||
<|highlight|> | ||
return [...previousState, data] <|highlight|> | ||
}, <|highlight|> | ||
["my initial message"] <|highlight|> | ||
) <|highlight|> | ||
|
||
return ( | ||
<Card className="not-prose"> | ||
<CardHeader> | ||
<CardTitle>Use Action State</CardTitle> | ||
</CardHeader> | ||
<CardContent className="flex flex-col gap-4"> | ||
<form action={submitAction} className="flex flex-col gap-4"> <|highlight|> | ||
<Input name="name" placeholder="Enter your name..." /> <|highlight|> | ||
<Button>Create message</Button> <|highlight|> | ||
</form> <|highlight|> | ||
<h1>Messages:</h1> | ||
<div> | ||
{messages.map((message, index) => ( | ||
<div key={index}>{message}</div> | ||
))} | ||
</div> | ||
</CardContent> | ||
</Card> | ||
) | ||
} | ||
``` | ||
|
||
### Result | ||
|
||
<ExampleComponent id="use-form-state" /> |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.