Серверные действия: Server Actions
Меняем данные на сервере, вызывая серверную функцию прямо из формы — без написания API-эндпоинта.
Server Action — асинхронная функция с директивой
'use server', которая выполняется только на сервере, но вызывается из клиента как обычная функция; идеальна для отправки форм и мутаций данных.
Зачем они нужны
Раньше, чтобы сохранить форму, нужно было: создать API-эндпоинт, написать fetch на клиенте, обработать ответ. Server Actions убирают эту прослойку: вы пишете серверную функцию и привязываете её прямо к форме.
Действие в форме
Объявляем функцию с 'use server' и передаём её в проп action формы. Браузер отправит данные формы, а функция выполнится на сервере:
// app/new/page.tsx — серверный компонент
import { db } from "@/lib/db";
export default function NewPostPage() {
async function createPost(formData) {
"use server";
const title = formData.get("title");
await db.posts.create({ data: { title } });
}
return (
<form action={createPost}>
<input name="title" />
<button type="submit">Создать</button>
</form>
);
}
Обратите внимание: никакого onSubmit, fetch или эндпоинта. Данные формы приходят как formData прямо на сервер.
Чем это безопасно
Код действия живёт на сервере: в браузер уходит только ссылка-идентификатор, а не сама логика. Поэтому в Server Action можно безопасно обращаться к БД и использовать секреты — они не утекают клиенту.
Прогрессивное улучшение
Поскольку действие привязано к <form>, форма работает даже до загрузки JavaScript — браузер отправит её штатно. Это называется прогрессивным улучшением. Смоделируем разбор formData на чистом JS:
// имитация FormData как массива пар [имя, значение]
const entries = [["title", "Привет"], ["tag", "next"], ["tag", "react"]];
const form = new Map();
for (const [k, v] of entries) {
if (form.has(k)) form.set(k, [].concat(form.get(k), v));
else form.set(k, v);
}
console.log("title:", form.get("title"));
console.log("tags:", form.get("tag"));
Вывод:
title: Привет tags: [ 'next', 'react' ]
Итог
- Server Action — серверная функция с
'use server', вызывается прямо из формы. - Не нужен отдельный API-эндпоинт и ручной
fetchдля мутаций. - Логика и секреты остаются на сервере; форма работает даже без JS.