|
2 | 2 | title: useSubmission
|
3 | 3 | ---
|
4 | 4 |
|
5 |
| -This helper is used to handle form submissions and can provide optimistic updates while actions are in flight as well as pending state feedback. |
6 |
| -This method will return a single (latest) value while its sibling, [`useSubmissions`](/solid-router/reference/data-apis/use-submissions), will return all values submitted while the component is active. With an optional second parameter for a filter function. |
| 5 | +The `useSubmission` function returns a submission object for a specified action. |
| 6 | +This submission object contains properties to access the state of action execution and functions to control the action. |
7 | 7 |
|
8 |
| -It's important to note that `useSubmission` requires the form method to be **post** otherwise it will trigger a browser navigation and will not work. |
9 |
| - |
10 |
| -```tsx title="component.tsx" {4,8} |
11 |
| -import { useSubmission } from "@solidjs/router"; |
12 |
| - |
13 |
| -function Component() { |
14 |
| - const submission = useSubmission(postNameAction); |
15 |
| - |
16 |
| - return ( |
17 |
| - <form action={postNameAction} method="post"> |
18 |
| - <input type="text" name="name" /> |
19 |
| - <button type="submit"> |
20 |
| - {submission.pending ? "Adding..." : "Add"} |
21 |
| - </button> |
22 |
| - </form> |
23 |
| - ) |
| 8 | +```tsx |
| 9 | +import { Show } from "solid-js"; |
| 10 | +import { action, useSubmission } from "@solidjs/router"; |
| 11 | + |
| 12 | +const addTodoAction = action(async (formData: FormData) => { |
| 13 | + const name = formData.get("name")?.toString() ?? ""; |
| 14 | + if (name.length <= 2) { |
| 15 | + throw new Error("Name must be larger than 2 characters"); |
| 16 | + } |
| 17 | +}, "addTodo"); |
| 18 | + |
| 19 | +function AddTodoForm() { |
| 20 | + const submission = useSubmission(addTodoAction); |
| 21 | + return ( |
| 22 | + <form action={addTodoAction} method="post"> |
| 23 | + <input name="name" /> |
| 24 | + <button type="submit">{submission.pending ? "Adding..." : "Add"}</button> |
| 25 | + <Show when={submission.error}> |
| 26 | + {(error) => ( |
| 27 | + <div> |
| 28 | + <p>{error().message}</p> |
| 29 | + <button onClick={() => submission.clear()}>Clear</button> |
| 30 | + <button onClick={() => submission.retry()}>Retry</button> |
| 31 | + </div> |
| 32 | + )} |
| 33 | + </Show> |
| 34 | + </form> |
| 35 | + ); |
24 | 36 | }
|
25 | 37 | ```
|
26 | 38 |
|
27 |
| -:::info |
28 |
| -Learn more about actions in the [`action`](/solid-router/reference/data-apis/action) docs. |
| 39 | +:::info[Note] |
| 40 | +If an action is executed multiple times, the last submission will be returned. |
| 41 | +To access all submissions, `useSubmissions`[/solid-router/reference/data-apis/use-submissions] can be used. |
29 | 42 | :::
|
30 | 43 |
|
31 |
| -## Filtering Submissions |
32 |
| - |
33 |
| -As an optional second parameter, the `useSubmission` helper can receive a filter function to only return the submission that matches the condition. |
34 |
| -The filter receives the submitted dated as a parameter and should return a boolean value. |
35 |
| -E.g.: action below will only submit if the name is "solid". |
36 |
| - |
37 |
| -```tsx title="component.tsx" {4-8} |
38 |
| -import { useSubmission } from "@solidjs/router"; |
39 |
| - |
40 |
| -function Component() { |
41 |
| - const submission = useSubmission(postNameAction, ([formData]) => { |
42 |
| - const name = formData.get("name") ?? ""; |
43 |
| - |
44 |
| - return name === "solid"; |
45 |
| - }); |
46 |
| - |
47 |
| - return ( |
48 |
| - <form action={postNameAction} method="post"> |
49 |
| - <input type="text" name="name" /> |
50 |
| - <button type="submit"> |
51 |
| - {submission.pending ? "Adding..." : "Add"} |
52 |
| - </button> |
53 |
| - </form> |
54 |
| - ) |
55 |
| -} |
56 |
| -``` |
57 |
| - |
58 |
| -## Optimistic Updates |
59 |
| - |
60 |
| -When the form is submitted, the `submission` object will be updated with the new value and the `pending` property will be set to `true`. |
61 |
| -This allows you to provide feedback to the user that the action is in progress. |
62 |
| -Once the action is complete, the `pending` property will be set to `false` and the `result` property will be updated with final value. |
63 |
| - |
64 |
| -```tsx tab title="TypeScript" {6,10-12} |
65 |
| -// component.tsx |
66 |
| -import { Show } from "solid-js"; |
67 |
| -import { useSubmission } from "@solidjs/router"; |
68 |
| - |
69 |
| -function Component() { |
70 |
| - const submission = useSubmission(postNameAction); |
71 |
| - |
72 |
| - return ( |
73 |
| - <> |
74 |
| - <Show when={submission.input?.[0].get("name")}> |
75 |
| - {(name) => <div>Optimistic: {name() as string}</div>} |
76 |
| - </Show> |
| 44 | +## Filter function |
77 | 45 |
|
78 |
| - <Show when={submission.result?.name}> |
79 |
| - {(name) => <div>Result: {name()}</div>} |
80 |
| - </Show> |
| 46 | +Optionally, `useSubmission` accepts a second parameter, which is a filter function. |
| 47 | +This function is executed for each submission and returns the first submission that passes through the filter. |
| 48 | +The filter function takes the submitted data as its parameter and should return `true` to select the submission and `false` otherwise. |
81 | 49 |
|
82 |
| - <form method="post" action={sendData}> |
83 |
| - <input type="text" name="name" required /> |
84 |
| - <button type="submit" disabled={submission.pending}> |
85 |
| - {submission.pending ? "Submitting" : "Submit"} |
86 |
| - </button> |
87 |
| - </form> |
88 |
| - </> |
89 |
| - ) |
90 |
| -} |
91 |
| -``` |
92 |
| - |
93 |
| -```tsx tab title="JavaScript" {6,10-12} |
94 |
| -// component.jsx |
95 |
| -import { Show } from "solid-js"; |
| 50 | +```tsx |
96 | 51 | import { useSubmission } from "@solidjs/router";
|
97 |
| - |
98 |
| -function Component() { |
99 |
| - const submission = useSubmission(postNameAction); |
100 |
| - |
101 |
| - return ( |
102 |
| - <> |
103 |
| - <Show when={submission.input?.[0].get("name")}> |
104 |
| - {(name) => <div>Optimistic: {name()}</div>} |
105 |
| - </Show> |
106 |
| - |
107 |
| - <Show when={submission.result?.name}> |
108 |
| - {(name) => <div>Result: {name()}</div>} |
109 |
| - </Show> |
110 |
| - |
111 |
| - <form method="post" action={sendData}> |
112 |
| - <input type="text" name="name" required /> |
113 |
| - <button type="submit" disabled={submission.pending}> |
114 |
| - {submission.pending ? "Submitting" : "Submit"} |
115 |
| - </button> |
116 |
| - </form> |
117 |
| - </> |
118 |
| - ) |
| 52 | +import { addTodoAction } from "./actions"; |
| 53 | + |
| 54 | +function LatestTodo() { |
| 55 | + const latestValidSubmission = useSubmission( |
| 56 | + addTodoAction, |
| 57 | + ([formData]: [FormData]) => { |
| 58 | + const name = formData.get("name")?.toString() ?? ""; |
| 59 | + return name.length > 2; |
| 60 | + } |
| 61 | + ); |
| 62 | + return <p>Latest valid submittion: {latestValidSubmission.result}</p>; |
119 | 63 | }
|
120 | 64 | ```
|
121 | 65 |
|
122 |
| -## Error Handling |
123 |
| - |
124 |
| -If the action fails, the `submission` object will be updated with the error and the `pending` property will be set to `false`. |
125 |
| -This allows you to provide feedback to the user that the action has failed. Additionally, the return type of `useSubmission` will have a new key `error` that will contain the error object thrown by the submission handler. |
126 |
| - |
127 |
| -At this stage, you can also use the `retry()` method to attempt the action again or the `clear()` to wipe the filled data in the platform. |
| 66 | +## Parameters |
128 | 67 |
|
129 |
| -```tsx title="component.tsx" {12-18} |
130 |
| -import { Show } from "solid-js"; |
131 |
| -import { useSubmission } from "@solidjs/router"; |
| 68 | +- **action**: The action for which you want to return submissions. |
| 69 | +- **filter** (Optional): The filter function that receives the submitted data as its parameter. |
| 70 | + It should return `true` if the submission passes the filter and `false` otherwise. |
132 | 71 |
|
133 |
| -function Component() { |
134 |
| - const submission = useSubmission(postNameAction); |
| 72 | +## Returns |
135 | 73 |
|
136 |
| - return ( |
137 |
| - <> |
138 |
| - <Show when={submission.error}> |
139 |
| - {(error) => ( |
140 |
| - <div> |
141 |
| - <p>Error: {error.message}</p> |
142 |
| - <button onClick={() => submission.clear()}> |
143 |
| - Clear |
144 |
| - </button> |
145 |
| - <button onClick={async () => submission.retry()}> |
146 |
| - Retry |
147 |
| - </button> |
148 |
| - </div> |
149 |
| - )} |
150 |
| - </Show> |
| 74 | +`useSubmission` returns an object containing the following properties: |
151 | 75 |
|
152 |
| - <form method="post" action={sendData}> |
153 |
| - <input type="text" name="name" required /> |
154 |
| - <button type="submit" disabled={submission.pending}> |
155 |
| - {submission.pending ? "Submitting" : "Submit"} |
156 |
| - </button> |
157 |
| - </form> |
158 |
| - </> |
159 |
| - ) |
160 |
| -} |
161 |
| -``` |
| 76 | +- **input**: The input data of the action. |
| 77 | +- **result**: The returned value of the action. |
| 78 | +- **error**: Any error thrown from the action. |
| 79 | +- **pending**: A boolean indicating whether the action is currently being executed. |
| 80 | +- **clear**: A function to clear the results of the submission. |
| 81 | +- **retry**: A function to re-execute the action. |
0 commit comments