Server actions let you change data easily without extra setup. They keep your app simple and fast.
Why server actions simplify mutations in NextJS
Start learning this pattern below
Jump into concepts and practice - no test required
export async function actionName(formData: FormData) { // handle mutation here // e.g., update database return redirect('/some-page') } export default function Page() { return ( <form action={actionName} method="post"> {/* form inputs */} <button type="submit">Submit</button> </form> ) }
Server actions are async functions exported from a component file.
They receive form data automatically when the form is submitted.
export async function addItem(formData: FormData) { const item = formData.get('item')?.toString() || ''; // save item to database return null; } export default function AddItem() { return ( <form action={addItem} method="post"> <input name="item" required /> <button type="submit">Add</button> </form> ) }
export async function deleteUser(formData: FormData) { const userId = formData.get('id')?.toString() || ''; // delete user from database return redirect('/users'); } export default function DeleteUser() { return ( <form action={deleteUser} method="post"> <input type="hidden" name="id" value="123" /> <button type="submit">Delete User</button> </form> ) }
This component shows a form to send a message. When submitted, the server action addMessage runs, saving the message and redirecting to '/messages'. This keeps mutation logic on the server and the UI simple.
import { redirect } from 'next/navigation'; export async function addMessage(formData: FormData) { const message = formData.get('message')?.toString() || ''; // Imagine saving message to a database here console.log('Message saved:', message); return redirect('/messages'); } export default function MessageForm() { return ( <main> <h1>Send a Message</h1> <form action={addMessage} method="post"> <label htmlFor="message">Message:</label> <textarea id="message" name="message" required rows={4} cols={30} /> <button type="submit">Send</button> </form> </main> ); }
Server actions run only on the server, so they keep secrets safe.
You don't need extra API routes or client-side fetch calls for simple mutations.
Use redirect() to send users to another page after mutation.
Server actions let you handle data changes directly on the server.
They simplify your code by removing the need for separate API endpoints.
This makes your app easier to write and maintain.
Practice
Solution
Step 1: Understand server actions role
Server actions let you run code on the server side directly from your components.Step 2: Identify how mutations are simplified
By running mutations on the server, you avoid extra API calls and client-side state management.Final Answer:
They allow you to update data directly on the server without extra API calls. -> Option CQuick Check:
Server actions simplify mutations = They allow you to update data directly on the server without extra API calls. [OK]
- Thinking server actions increase client code
- Believing server actions slow down the app
- Confusing server actions with static data only
Solution
Step 1: Recognize server action syntax
Server actions are exported async functions that run on the server.Step 2: Check options for server-side export
Only export async function updateData() { /* server code */ } exports an async function suitable for server actions.Final Answer:
export async function updateData() { /* server code */ } -> Option AQuick Check:
Server action syntax = export async function updateData() { /* server code */ } [OK]
- Using arrow functions without export
- Writing client-side fetch inside server action
- Not marking function as async
export async function incrementCounter() {
// Imagine this updates a database
return 1;
}
export default function Counter() {
const [count, setCount] = React.useState(0);
async function handleClick() {
const result = await incrementCounter();
setCount(count + result);
}
return Count: {count};
}Solution
Step 1: Understand server action return value
incrementCounter returns 1 simulating a database update.Step 2: Analyze handleClick behavior
handleClick awaits incrementCounter and adds the result to count state.Final Answer:
The count will increase by 1 each time the button is clicked. -> Option AQuick Check:
Server action returns 1, count increments by 1 [OK]
- Assuming server actions can't be awaited
- Thinking async causes syntax errors
- Ignoring the returned value from server action
export async function saveData() {
await fetch('/api/save', { method: 'POST' });
}
export default function SaveButton() {
function handleClick() {
saveData();
alert('Saved!');
}
return Save;
}Solution
Step 1: Check async usage in handleClick
handleClick calls saveData but does not await it, so alert runs immediately.Step 2: Fix by making handleClick async and awaiting saveData
This ensures data is saved before alert shows.Final Answer:
handleClick should be async and await saveData to ensure save completes before alert. -> Option BQuick Check:
Await server action before alert = handleClick should be async and await saveData to ensure save completes before alert. [OK]
- Not awaiting async functions causing race conditions
- Thinking fetch is disallowed in server actions
- Misunderstanding alert usage in React
1. Create a server action to update the profile.
2. Call the server action directly from the component.
3. Use React state to store updated profile.
4. Avoid extra API calls or client-side fetching.
Solution
Step 1: Use server action for mutation and return updated data
This avoids extra API calls and keeps logic on server.Step 2: Await server action in component and update React state
This refreshes UI with new data immediately and simply.Final Answer:
Define an async server action that updates the profile and returns updated data, then update React state with this data after awaiting the action. -> Option DQuick Check:
Server action mutation + update state = Define an async server action that updates the profile and returns updated data, then update React state with this data after awaiting the action. [OK]
- Using client fetch instead of server actions
- Not updating React state after mutation
- Thinking server actions can't return data
