Skip to content

Fix useSubmission/useSubmissions and action docs #1179

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

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
205 changes: 64 additions & 141 deletions src/routes/solid-router/reference/data-apis/use-submission.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,160 +2,83 @@
title: useSubmission
---

This helper is used to handle form submissions and can provide optimistic updates while actions are in flight as well as pending state feedback.
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.
The `useSubmission` function retrieves the state of the most recent submission for a given action.

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.

```tsx title="component.tsx" {4,8}
import { useSubmission } from "@solidjs/router";

function Component() {
const submission = useSubmission(postNameAction);

return (
<form action={postNameAction} method="post">
<input type="text" name="name" />
<button type="submit">
{submission.pending ? "Adding..." : "Add"}
</button>
</form>
)
```tsx
import { Show } from "solid-js";
import { action, useSubmission } from "@solidjs/router";

const addTodoAction = action(async (formData: FormData) => {
const name = formData.get("name")?.toString() ?? "";
if (name.length <= 2) {
throw new Error("Name must be larger than 2 characters");
}
}, "addTodo");

function AddTodoForm() {
const submission = useSubmission(addTodoAction);
return (
<form action={addTodoAction} method="post">
<input name="name" />
<button type="submit">{submission.pending ? "Adding..." : "Add"}</button>
<Show when={submission.error}>
{(error) => (
<div>
<p>{error().message}</p>
<button onClick={() => submission.clear()}>Clear</button>
<button onClick={() => submission.retry()}>Retry</button>
</div>
)}
</Show>
</form>
);
}
```

:::info
Learn more about actions in the [`action`](/solid-router/reference/data-apis/action) docs.
:::info[Note]
To access the state of all submissions, `useSubmissions`[/solid-router/reference/data-apis/use-submissions] can be used.
:::

## Filtering Submissions

As an optional second parameter, the `useSubmission` helper can receive a filter function to only return the submission that matches the condition.
The filter receives the submitted dated as a parameter and should return a boolean value.
E.g.: action below will only submit if the name is "solid".

```tsx title="component.tsx" {4-8}
import { useSubmission } from "@solidjs/router";

function Component() {
const submission = useSubmission(postNameAction, ([formData]) => {
const name = formData.get("name") ?? "";

return name === "solid";
});

return (
<form action={postNameAction} method="post">
<input type="text" name="name" />
<button type="submit">
{submission.pending ? "Adding..." : "Add"}
</button>
</form>
)
}
```

## Optimistic Updates

When the form is submitted, the `submission` object will be updated with the new value and the `pending` property will be set to `true`.
This allows you to provide feedback to the user that the action is in progress.
Once the action is complete, the `pending` property will be set to `false` and the `result` property will be updated with final value.

```tsx tab title="TypeScript" {6,10-12}
// component.tsx
import { Show } from "solid-js";
import { useSubmission } from "@solidjs/router";

function Component() {
const submission = useSubmission(postNameAction);

return (
<>
<Show when={submission.input?.[0].get("name")}>
{(name) => <div>Optimistic: {name() as string}</div>}
</Show>
## Filter function

<Show when={submission.result?.name}>
{(name) => <div>Result: {name()}</div>}
</Show>
The `useSubmission` function optionally accepts a second parameter, which is a filter function.
This function is executed for each submission in the order they were created, and the first submission that meet the filter criteria is returned by `useSubmission`.
The filter function recieves the input data of the action as its parameter and must return `true` to select the submission or `false` otherwise.

<form method="post" action={sendData}>
<input type="text" name="name" required />
<button type="submit" disabled={submission.pending}>
{submission.pending ? "Submitting" : "Submit"}
</button>
</form>
</>
)
}
```

```tsx tab title="JavaScript" {6,10-12}
// component.jsx
import { Show } from "solid-js";
```tsx
import { useSubmission } from "@solidjs/router";

function Component() {
const submission = useSubmission(postNameAction);

return (
<>
<Show when={submission.input?.[0].get("name")}>
{(name) => <div>Optimistic: {name()}</div>}
</Show>

<Show when={submission.result?.name}>
{(name) => <div>Result: {name()}</div>}
</Show>

<form method="post" action={sendData}>
<input type="text" name="name" required />
<button type="submit" disabled={submission.pending}>
{submission.pending ? "Submitting" : "Submit"}
</button>
</form>
</>
)
import { addTodoAction } from "./actions";

function LatestTodo() {
const latestValidSubmission = useSubmission(
addTodoAction,
([formData]: [FormData]) => {
const name = formData.get("name")?.toString() ?? "";
return name.length > 2;
}
);
return <p>Latest valid submission: {latestValidSubmission.result}</p>;
}
```

## Error Handling

If the action fails, the `submission` object will be updated with the error and the `pending` property will be set to `false`.
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.

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

```tsx title="component.tsx" {12-18}
import { Show } from "solid-js";
import { useSubmission } from "@solidjs/router";
- **action**: The action for which you want to get the most recent submission.
- **filter** (optional): A filter function.
When provided, it executes on each submission in the order of creation, returning the first submission that passes the filter.
It receives the input data of the action as its parameter and must return `true` for the submission to be selected and `false` otherwise.

function Component() {
const submission = useSubmission(postNameAction);
## Returns

return (
<>
<Show when={submission.error}>
{(error) => (
<div>
<p>Error: {error.message}</p>
<button onClick={() => submission.clear()}>
Clear
</button>
<button onClick={async () => submission.retry()}>
Retry
</button>
</div>
)}
</Show>
`useSubmission` returns an object containing the following properties:

<form method="post" action={sendData}>
<input type="text" name="name" required />
<button type="submit" disabled={submission.pending}>
{submission.pending ? "Submitting" : "Submit"}
</button>
</form>
</>
)
}
```
- **input**: The input data of the action.
This is a reactive value.
- **result**: The value returned from the action.
This is a reactive value.
- **error**: Any error thrown from the action.
This is a reactive value.
- **pending**: A boolean indicating whether the action is currently being executed.
This is a reactive value.
- **clear**: A function that clears the result of the submission.
- **retry**: A function that re-executes the submission with the same input.
Loading