Data APIs

action

Edit this page

Actions 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"
// anywhere
const 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 component
const 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))
})
// ...
}
Report an issue with this page