Action functions let you handle changes like form submissions on the server. They help update data safely and keep your app interactive.
Action functions for mutations in Remix
import { redirect } from '@remix-run/node'; export async function action({ request }) { const formData = await request.formData(); // process formData and perform mutation return redirect('/some-path'); }
The action function runs on the server when a form is submitted.
You get the request object to read form data or JSON.
import { redirect } from '@remix-run/node'; export async function action({ request }) { const formData = await request.formData(); const name = formData.get('name'); // save name to database return redirect('/thank-you'); }
import { json } from '@remix-run/node'; export async function action({ request }) { const data = await request.json(); // update database with JSON data return json({ success: true }); }
This example shows a simple contact form. When submitted, the action function reads the message, logs it, and redirects the user to a thank-you page.
import { redirect } from '@remix-run/node'; export async function action({ request }) { const formData = await request.formData(); const message = formData.get('message'); // Imagine saving message to a database here console.log('Received message:', message); return redirect('/thank-you'); } export default function Contact() { return ( <form method="post" aria-label="Contact form"> <label htmlFor="message">Message:</label> <textarea id="message" name="message" required></textarea> <button type="submit">Send</button> </form> ); }
Action functions only run on the server, so you can safely handle secrets and database updates.
Always return a response like redirect() or json() to tell Remix what to do next.
Use method="post" on your form to trigger the action function.
Action functions handle form submissions and data changes on the server.
They receive the request and let you read form or JSON data.
Return a redirect or JSON response to control what happens after mutation.
Practice
action function in Remix?Solution
Step 1: Understand the role of action functions
Action functions in Remix are designed to handle mutations like form submissions or data updates on the server side.Step 2: Differentiate from loaders and client handlers
Loaders fetch data for rendering, client handlers manage UI events, and styling is unrelated to action functions.Final Answer:
To handle form submissions and update data on the server -> Option AQuick Check:
Action functions = handle mutations [OK]
- Confusing action with loader functions
- Thinking action runs on the client
- Assuming action handles styling or UI only
action function in a Remix route module?Solution
Step 1: Recall Remix action function syntax
Action functions must be exported async functions receiving an object with the request property.Step 2: Identify correct export and parameters
export async function action({ request }) { /* code */ } correctly exports an async function named action with { request } parameter.Final Answer:
export async function action({ request }) { /* code */ } -> Option AQuick Check:
Correct export and async function = export async function action({ request }) { /* code */ } [OK]
- Not exporting the function
- Using loader instead of action
- Missing async keyword
export async function action({ request }) {
const formData = await request.formData();
const name = formData.get('name');
if (!name) {
return new Response('Name is required', { status: 400 });
}
return redirect('/thank-you');
}Solution
Step 1: Analyze formData extraction and validation
The function extracts 'name' from formData and checks if it exists.Step 2: Determine response based on validation
If 'name' is missing, it returns a 400 error response; otherwise, it redirects to '/thank-you'.Final Answer:
Redirects to '/thank-you' if name is provided, else returns 400 error -> Option BQuick Check:
Validation controls redirect or error [OK]
- Assuming redirect always happens
- Ignoring the 400 error response
- Thinking it returns JSON
export async function action({ request }) {
const data = await request.json();
if (!data.title) {
return json({ error: 'Title missing' }, 400);
}
// save data logic
return redirect('/success');
}Solution
Step 1: Check json() function usage
The Remix json() helper expects an options object for status, not a separate number argument.Step 2: Identify correct json() call
The correct call is json({ error: 'Title missing' }, { status: 400 }) instead of json({ error: 'Title missing' }, 400).Final Answer:
Incorrect usage of json() function with status code as second argument -> Option DQuick Check:
json() status must be in options object [OK]
- Passing status code as separate argument
- Forgetting to import json helper
- Assuming redirect needs await
Solution
Step 1: Understand server-side authentication in action
Action functions run on server, so checking user session here ensures secure mutation.Step 2: Implement conditional logic for authentication
If user is not authenticated, redirect to login; otherwise, perform update and redirect to profile page.Final Answer:
Check user session inside action; if no user, return redirect to login; else update and redirect to profile -> Option CQuick Check:
Secure mutation requires server auth check in action [OK]
- Relying only on loader for auth
- Skipping auth check in action
- Using client-side auth only
Ready to prove it?
Pass the test and this pattern moves unknown
