action
Edit this pageActions are data mutations that can trigger invalidations and further routing. A list of prebuilt response helpers can be found below.
import { action, revalidate, redirect } from "@solidjs/router"
// anywhereconst myAction = action(async (data) => { await doMutation(data); throw redirect("/", { revalidate: getUser.keyFor(data.id) }); // throw a response to do a redirect});
// in component<form action={myAction} method="post" />
//or<button type="submit" formaction={myAction}></button>
Actions only work with post requests.
This means forms require method="post"
.
A with
method can be used when typed data is required.
This removes the need to use FormData
or other additional hidden fields.
The with
method works similar to bind
, which applies the arguments in order.
Without with
:
const deleteTodo = action(async (formData: FormData) => { const id = Number(formData.get("id")) await api.deleteTodo(id)})
<form action={deleteTodo} method="post"> <input type="hidden" name="id" value={todo.id} /> <button type="submit">Delete</button></form>
Using with
:
const deleteTodo = action(async (formData: FormData) => { const id = Number(formData.get("id")) await api.deleteTodo(id)})
<form action={deleteTodo} method="post"> <input type="hidden" name="id" value={todo.id} /><form action={deleteTodo.with(todo.id)} method="post"> <button type="submit">Delete</button></form>
Notes of <form>
implementation and SSR
This requires stable references because a string can only be serialized as an attribute, and it is crucial for consistency across SSR. where these references must align. The solution is to provide a unique name.
const myAction = action(async (args) => {}, "my-action");
useAction
Instead of forms, actions can directly be wrapped in a useAction
primitive.
This is how router context is created.
// in componentconst submit = useAction(myAction);submit(...args);
The outside of a form context can use custom data instead of formData
.
These helpers preserve types.
However, even when used with server functions, such as with SolidStart, this requires client-side JavaScript and is not progressively enhanceable like forms are.
useSubmission
/useSubmissions
These functions are used when incorporating optimistic updates during ongoing actions. They provide either a singular Submission (the latest one), or a collection of Submissions that match, with an optional filtering function.
type Submission<T, U> = { input: T; result: U; error: any; pending: boolean clear: () => {} retry: () => {}}
const submissions = useSubmissions(action, (input) => filter(input));const submission = useSubmission(action, (input) => filter(input));
Revalidate cached functions
Revalidate all (default)
By default all cached functions will be revalidated wether the action does not return or return a "normal" response.
const deleteTodo = action(async (formData: FormData) => { const id = Number(formData.get("id")) await api.deleteTodo(id) // ... return new Response("success", { status: 200 });})
Revalidate specific cached keys
By returning a response with solid-router's json
, reload
or redirect
helpers you can pass a key / keys to the revalidate prop as the second argument of the json response helper.
You can either pass as string
directly or use the cached functions key
or keyFor
props.
import { action, json, reload, redirect } from "@solidjs/router"
const deleteTodo = action(async (formData: FormData) => { const id = Number(formData.get("id")) await api.deleteTodo(id) return json( { deleted: id }, { revalidate: ["getAllTodos", getTodos.key, getTodoByID.keyFor(id)]} )
//or return reload({ revalidate: ["getAllTodos", getTodos.key, getTodoByID.keyFor(id)]})
//or return redirect("/", { revalidate: ["getAllTodos", getTodos.key, getTodoByID.keyFor(id)]})
})
Prevent revalidation
To opt out of any revalidation you can pass any string
to revalidate which is not a key of any cached function.
const deleteTodo = action(async (formData: FormData) => { const id = Number(formData.get("id")) await api.deleteTodo(id) // returns a `json` without revalidating the action. return json(`deleted ${id}`,{ revalidate: "nothing" })
// or reload the route without revalidating the request. return reload({ revalidate: "nothing" })
// or redirect without revalidating return redirect("/", { revalidate: "nothing" })})
Revalidate without action
Cached functions can also be revalidated by the revalidate
helper.
revalidate([getTodos.key, getTodoByID.keyFor(id)])
This is also great if you want to set your own "refresh" interval e.g. poll data every 30 seconds.
export default function TodoLayout(){
const todos = createAsync(() => getTodos())
onMount(() => { //30 second polling const interval = setInterval(() => revalidate(getTodos.key),1000 * 30) onCleanup(() => clearInterval(interval)) })
// ...}