|
2 | 2 | title: useSubmissions
|
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 an iterable of all submitted actions while its component is mounted. With an optional second parameter for a filter function. |
7 |
| - |
8 |
| -:::tip |
9 |
| -If you only care for the latest submission, you can use the [`useSubmission`](/solid-router/reference/data-apis/use-submission) helper. |
10 |
| -::: |
11 |
| - |
12 |
| -It's important to note that it requires the form method to be **post** otherwise it will trigger a browser navigation and will not work. |
13 |
| - |
14 |
| -In the example below, the `useSubmissions` helper is used to retain a list of all submission results to that action while also giving feedback on the pending state of the current in-flight submission. |
15 |
| - |
16 |
| -```tsx title="component.tsx" {4,9-20, 23} |
17 |
| -import { useSubmissions } from "@solidjs/router"; |
18 |
| - |
19 |
| -function Component() { |
20 |
| - const submissions = useSubmissions(postNameAction); |
21 |
| - |
22 |
| - return ( |
23 |
| - <form method="post" action={postNameAction}> |
24 |
| - <ul> |
25 |
| - <For each={Array.from(submissions.entries())}> |
26 |
| - {([attemptIndex, data]) => ( |
27 |
| - <Show when={data.result}> |
28 |
| - { result => ( |
29 |
| - <li> |
30 |
| - Backend {attemptIndex}: {result.name} |
31 |
| - </li> |
32 |
| - )} |
33 |
| - </Show> |
34 |
| - </> |
35 |
| - )} |
36 |
| - </For> |
37 |
| - </ul> |
38 |
| - <input name="name" type="text" /> |
39 |
| - <button type="submit">{submissions.pending ? "sending" : "send"}</button> |
40 |
| - </form> |
41 |
| - ) |
| 5 | +The `useSubmissions` function retrieves the state of all submissions for a given action. |
| 6 | + |
| 7 | +```tsx |
| 8 | +import { For, Show } from "solid-js"; |
| 9 | +import { action, useSubmissions } from "@solidjs/router"; |
| 10 | + |
| 11 | +const addTodoAction = action(async (formData: FormData) => { |
| 12 | + const name = formData.get("name")?.toString() ?? ""; |
| 13 | + if (name.length <= 2) { |
| 14 | + throw new Error("Name must be larger than 2 characters"); |
| 15 | + } |
| 16 | + return name; |
| 17 | +}, "addTodo"); |
| 18 | + |
| 19 | +export default function AddTodoForm() { |
| 20 | + const submissions = useSubmissions(addTodoAction); |
| 21 | + return ( |
| 22 | + <div> |
| 23 | + <form action={addTodoAction} method="post"> |
| 24 | + <input name="name" /> |
| 25 | + <button type="submit">Add</button> |
| 26 | + </form> |
| 27 | + <For each={submissions}> |
| 28 | + {(submission) => ( |
| 29 | + <div> |
| 30 | + <span>Adding "{submission.input[0].get("name")?.toString()}"</span> |
| 31 | + <Show when={submission.pending}> |
| 32 | + <span> (pending...)</span> |
| 33 | + </Show> |
| 34 | + <Show when={submission.result}> |
| 35 | + <span> (completed)</span> |
| 36 | + </Show> |
| 37 | + <Show when={submission.error}> |
| 38 | + {(error) => ( |
| 39 | + <> |
| 40 | + <span>{` (Error: ${error().message})`}</span> |
| 41 | + <button onClick={() => submission.retry()}>Retry</button> |
| 42 | + </> |
| 43 | + )} |
| 44 | + </Show> |
| 45 | + </div> |
| 46 | + )} |
| 47 | + </For> |
| 48 | + </div> |
| 49 | + ); |
42 | 50 | }
|
43 | 51 | ```
|
44 | 52 |
|
45 |
| -:::note |
46 |
| -To trigger a submission, [actions](https://docs.solidjs.com/) can be used. |
| 53 | +:::info[Note] |
| 54 | +To access the state of the most recent submission, `useSubmission`[/solid-router/reference/data-apis/use-submission] can be used. |
47 | 55 | :::
|
48 | 56 |
|
49 |
| -## Filtering Submissions |
| 57 | +## Filter function |
50 | 58 |
|
51 |
| -As an optional second parameter, the `useSubmissions` helper can receive a filter function to only return the submission that matches the condition. |
52 |
| -The filter receives the submitted dated as a parameter and should return a boolean value. |
53 |
| -E.g.: action below will only submit if the name is "solid". |
| 59 | +The `useSubmissions` function optionally accepts a second parameter, which is a filter function. |
| 60 | +This function is executed for each submission in the order they were created, and only the submissions that meet the filter criteria are returned by `useSubmissions`. |
| 61 | +The filter function recieves the input data of the action as its parameter and must return `true` to select the submission or `false` otherwise. |
54 | 62 |
|
55 |
| -```tsx title="component.tsx" {4-8} |
| 63 | +```tsx |
56 | 64 | import { useSubmissions } from "@solidjs/router";
|
57 |
| - |
58 |
| -function Component() { |
59 |
| - const submissions = useSubmissions(postNameAction, ([formData]) => { |
60 |
| - const name = formData.get("name") ?? ""; |
61 |
| - |
62 |
| - return name === "solid"; |
63 |
| - }); |
64 |
| - |
65 |
| - return ( |
66 |
| - <form method="post" action={postNameAction}> |
67 |
| - <ul> |
68 |
| - <For each={Array.from(submissions.entries())}> |
69 |
| - {([attemptIndex, data]) => ( |
70 |
| - <Show when={data.result}> |
71 |
| - { result => ( |
72 |
| - <li> |
73 |
| - Backend {attemptIndex}: {result.name} |
74 |
| - </li> |
75 |
| - )} |
76 |
| - </Show> |
77 |
| - </> |
78 |
| - )} |
79 |
| - </For> |
80 |
| - </ul> |
81 |
| - <input name="name" type="text" /> |
82 |
| - <button type="submit">{submissions.pending ? "sending" : "send"}</button> |
83 |
| - </form> |
84 |
| - ) |
| 65 | +import { addTodoAction } from "./actions"; |
| 66 | + |
| 67 | +function FailedTodos() { |
| 68 | + const failedSubmissions = useSubmissions( |
| 69 | + addTodoAction, |
| 70 | + ([formData]: [FormData]) => { |
| 71 | + const name = formData.get("name")?.toString() ?? ""; |
| 72 | + return name.length <= 2; |
| 73 | + } |
| 74 | + ); |
| 75 | + return ( |
| 76 | + <div> |
| 77 | + <p>Failed submissions:</p> |
| 78 | + <For each={failedSubmissions}> |
| 79 | + {(submission) => ( |
| 80 | + <div> |
| 81 | + <span>{submission.input[0].get("name")?.toString()}</span> |
| 82 | + <button onClick={() => submission.retry()}>Retry</button> |
| 83 | + </div> |
| 84 | + )} |
| 85 | + </For> |
| 86 | + </div> |
| 87 | + ); |
85 | 88 | }
|
86 | 89 | ```
|
87 | 90 |
|
88 |
| -## Optimistic Updates |
89 |
| - |
90 |
| -When the form is submitted, the `submission` object will be updated with the new value and the `pending` property will be set to `true`. |
91 |
| -This allows you to provide feedback to the user that the action is in progress. |
92 |
| -Once the action is complete, the `pending` property will be set to `false` and the `result` property will be updated with final value. |
| 91 | +## Parameters |
93 | 92 |
|
94 |
| -```tsx tab title="TypeScript" {6,13-20} |
95 |
| -// component.tsx |
96 |
| -import { Show } from "solid-js"; |
97 |
| -import { useSubmissions } from "@solidjs/router"; |
98 |
| - |
99 |
| -function Component() { |
100 |
| - const submissions = useSubmissions(postNameAction); |
| 93 | +- **action**: The action for which you want to get the submissions. |
| 94 | +- **filter** (optional): A filter function. |
| 95 | + When provided, it executes on each submission in the order of creation, returning the submissions that pass the filter. |
| 96 | + It receives the input data of the action as its parameter and must return `true` to select the submission and `false` otherwise. |
101 | 97 |
|
102 |
| - return ( |
103 |
| - <form method="post" action={postNameAction}> |
104 |
| - <ul> |
105 |
| - <For each={Array.from(submissions.entries())}> |
106 |
| - {([attemptIndex, data]) => ( |
107 |
| - <Show when={data.input[0].entries().next()}> |
108 |
| - {(input) => { |
109 |
| - const name = (input().value as [string, string])[1] |
| 98 | +## Returns |
110 | 99 |
|
111 |
| - return ( |
112 |
| - <li>Optimistic: {name}</li> |
113 |
| - )}} |
114 |
| - </Show> |
115 |
| - )} |
116 |
| - </For> |
117 |
| - </ul> |
118 |
| - <input name="name" type="text" /> |
119 |
| - <button type="submit">{submissions.pending ? "sending" : "send"}</button> |
120 |
| - </form> |
121 |
| - ) |
122 |
| -} |
123 |
| -``` |
| 100 | +`useSubmissions` returns an array of submissions. |
| 101 | +Each submission is an object containing the following properties: |
124 | 102 |
|
125 |
| -```tsx tab title="JavaScript" {6,13-20} |
126 |
| -// component.jsx |
127 |
| -import { Show } from "solid-js"; |
128 |
| -import { useSubmissions } from "@solidjs/router"; |
129 |
| - |
130 |
| -function Component() { |
131 |
| - const submissions = useSubmissions(postNameAction); |
132 |
| - |
133 |
| - return ( |
134 |
| - <form method="post" action={postNameAction}> |
135 |
| - <ul> |
136 |
| - <For each={Array.from(submissions.entries())}> |
137 |
| - {([attemptIndex, data]) => ( |
138 |
| - <Show when={data.input[0].entries().next()}> |
139 |
| - {(input) => { |
140 |
| - const name = input().value[1] |
141 |
| - |
142 |
| - return ( |
143 |
| - <li>Optimistic: {name}</li> |
144 |
| - )}} |
145 |
| - </Show> |
146 |
| - )} |
147 |
| - </For> |
148 |
| - </ul> |
149 |
| - <input name="name" type="text" /> |
150 |
| - <button type="submit">{submissions.pending ? "sending" : "send"}</button> |
151 |
| - </form> |
152 |
| - ) |
153 |
| -} |
154 |
| -``` |
155 |
| - |
156 |
| -## Error Handling |
157 |
| - |
158 |
| -If the action fails, the `submission` object will be updated with the error and the `pending` property will be set to `false`. |
159 |
| -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. |
160 |
| - |
161 |
| -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. |
162 |
| - |
163 |
| -```tsx title="component.tsx" {12-18} |
164 |
| -import { Show } from "solid-js"; |
165 |
| -import { useSubmissions } from "@solidjs/router"; |
166 |
| - |
167 |
| -function Component() { |
168 |
| - const submissions = useSubmissions(postNameAction); |
169 |
| - |
170 |
| - return ( |
171 |
| - <form method="post" action={postNameAction}> |
172 |
| - <ul> |
173 |
| - <For each={Array.from(submissions.entries())}> |
174 |
| - {([attempt, data]) => ( |
175 |
| - <Show when={data.error}> |
176 |
| - <li> |
177 |
| - <p>Backend {attempt}: {data.error.message}</p> |
178 |
| - <button onClick={() => data.retry()}>retry</button> |
179 |
| - <button onClick={() => data.clear()}>clear</button> |
180 |
| - </li> |
181 |
| - </Show> |
182 |
| - )} |
183 |
| - </For> |
184 |
| - </ul> |
185 |
| - <input name="name" type="text" required autocomplete="off" /> |
186 |
| - <button type="submit">{submissions.pending ? "sending" : "send"}</button> |
187 |
| - </form> |
188 |
| - ) |
189 |
| -} |
190 |
| -``` |
| 103 | +- **input**: The input data of the action. |
| 104 | + This is a reactive value. |
| 105 | +- **result**: The value returned from the action. |
| 106 | + This is a reactive value. |
| 107 | +- **error**: Any error thrown from the action. |
| 108 | + This is a reactive value. |
| 109 | +- **pending**: A boolean indicating whether the action is currently being executed. |
| 110 | + This is a reactive value. |
| 111 | +- **clear**: A function that clears the result of the submission. |
| 112 | +- **retry**: A function that re-executes the submission with the same input. |
0 commit comments