Defining an Action

Just like loaders, we define Actions as exported named functions in route modules. Actions correlate to the POST request to the route. It's server side code that performs it's "action" and then re-hydrates the server with the response.

export async function action({ request }) { const formData = await request.formData(); const name = formData.get('name'); const email = formData.get('email'); const { id } = await createAuthor(name, email); return redirect('/authors/{id}'); // incorrect syntax but my CodeBlock plugin doesn't have a fix :) }

Form Data

I was shocked I didn't know this until learning Remix, but your browser has a FormData API. It's a key/value interface that can be easily sent over fetch or XMLHttpRequest.

The <Form /> component takes the data your users fill out and sends it to the routes corresponding action. Then in the action we're able to access that form data: request.formData().

One caveat is that the name and email values are FormDataEntryValue types and not strings. They can be casted though! There are better ways to handle this form data and validate in the action, but this is a simple example!

Action Response

The next part is the response. In the above action we're returning a redirect to the browser. We get the id of the author we just created and then go to the individual page for them.

In some cases you don't want to navigate to a new page after you submit data. In that case you can return json like you do from loaders!

Handling Errors

What if your action had errors! Maybe thhe user forgot to add an email! Since we can return json from loaders we can load that data into a route and display error messages:

export function action() { return json({ message: 'Name required!' }, { status: 500 } ); } export default function Route() { const data = useActionData<typeof action>(); return (<p>{data?.message ?? ""}</p>); }

We can call useActionData to pull in the response from our action. Keep in mind that this is undefined until the action is invoked!

There's a lot of levers Remix gives us to customize these actions. We don't always want to mutate from a form - or maybe we have multiple actions that need to be on the same route. Maybe we aren't posting data but still need to indicate a mutation should occur. Remix covers many different use cases pretty easily.

Let's try out actions for ourselves.