1. Синтаксис Server Action: async + "use server"
Если говорить простыми словами, Server Action — это обычная асинхронная функция, которая объявляется в Server Component и помечается специальной директивой "use server". Эта функция будет выполняться только на сервере, даже если её вызов инициируется из браузера (например, при отправке формы).
Server Actions позволяют:
- Обрабатывать данные формы на сервере без промежуточных API.
- Выполнять любые серверные операции (запросы к базе, отправку писем, работу с секретами).
- Возвращать результат обратно в компонент или обновлять состояние.
Ключевая особенность: Server Action — это не просто функция, а "endpoint по требованию", который создаётся и вызывается автоматически, когда этого требует Next.js.
Основные правила
- Server Action — это асинхронная функция (async function).
- В начале тела функции обязательно должна быть строка "use server".
- Функция должна быть объявлена или импортирована в Server Component (или в отдельном серверном модуле).
- Эту функцию можно передавать как обработчик события (например, action формы).
Пример минимального Server Action
// app/actions/sendMessage.js
'use server'
export async function sendMessage(formData) {
// Здесь можно делать всё, что нужно на сервере
const message = formData.get('message');
// Например, сохранить в базу или отправить email
console.log('Сообщение с формы:', message);
}
Важно: Директива "use server" должна быть первой строкой в файле (или в теле функции, если функция объявляется внутри компонента).
2. Где объявлять Server Actions
Server Actions могут быть объявлены:
- Внутри Server Component (например, прямо внутри page.js или page.tsx)
- В отдельном файле в папке app/actions/ или где угодно в серверной части проекта
Рекомендуемый подход: выносить Server Actions в отдельные модули, чтобы их можно было переиспользовать и тестировать.
Пример: объявление внутри компонента
// app/contact/page.jsx
export default function ContactPage() {
async function submit(formData) {
'use server'
const name = formData.get('name');
// ... логика на сервере
}
return (
<form action={submit}>
<input name="name" />
<button type="submit">Отправить</button>
</form>
);
}
Пример: импорт из отдельного файла
// app/actions/sendMessage.js
'use server'
export async function sendMessage(formData) {
// ...
}
// app/contact/page.jsx
import { sendMessage } from '../actions/sendMessage';
export default function ContactPage() {
return (
<form action={sendMessage}>
<input name="name" />
<button type="submit">Отправить</button>
</form>
);
}
3. Как работает "use server" под капотом
Строка "use server" — это не просто украшение для кода. Она сообщает Next.js (и сборщику), что функция должна выполняться только на сервере и может быть вызвана из браузера через специальный механизм сериализации и десериализации.
- Если вы попытаетесь вызвать такую функцию на клиенте напрямую — получите ошибку.
- При отправке формы с атрибутом action={serverAction} Next.js сам отправит POST-запрос на сервер, вызовет вашу функцию, а затем обновит компонент.
Аналогия:
Можно представить, что "use server" — это как огромная табличка "Вход только для сотрудников". Если вы не сервер — не лезьте сюда!
Получение данных в Server Action: FormData
Server Action по умолчанию принимает объект FormData — это стандартный способ передачи данных из формы.
Пример: получение значений из формы
'use server'
export async function addTodo(formData) {
const title = formData.get('title');
const description = formData.get('description');
// Теперь можно сохранить задачу в базу, отправить e-mail и т.д.
}
Важный нюанс:
FormData — это не обычный объект JavaScript! Для получения значения поля используйте formData.get('имя_поля').
4. Пример: простая форма с Server Action
Давайте соберём всё вместе и реализуем минимальное приложение "Добавить задачу" с помощью Server Action.
Шаг 1. Создаём Server Action
// app/actions/addTodo.js
'use server'
export async function addTodo(formData) {
const title = formData.get('title');
// Здесь можно добавить задачу в базу или массив
console.log('Добавлена задача:', title);
}
Шаг 2. Используем в компоненте
// app/todos/page.jsx
import { addTodo } from '../actions/addTodo';
export default function TodosPage() {
return (
<form action={addTodo}>
<input name="title" placeholder="Новая задача" />
<button type="submit">Добавить</button>
</form>
);
}
Как это работает?
- Пользователь заполняет поле и нажимает "Добавить".
- Next.js сериализует данные формы, отправляет их на сервер.
- На сервере вызывается функция addTodo, которая получает данные и делает всё, что нужно.
- После выполнения Server Action страница может быть автоматически обновлена (или вы сами решаете, что делать дальше).
5. Полезные нюансы
Можно ли передавать не только FormData?
Да! Server Action может принимать любые сериализуемые параметры, но по умолчанию, если вы используете <form action={...}> — в функцию попадёт именно FormData.
Если вы хотите вызвать Server Action программно (например, из Client Component через специальный API), параметры должны быть сериализуемыми (то есть простые объекты, числа, строки и т.д.).
Типовой паттерн — работа с формами через FormData.
Асинхронность и side effects
Server Actions — всегда асинхронные. Это значит, что внутри можно:
- Делать запросы к базе данных (await db.insert(...))
- Вызывать сторонние API
- Работать с файловой системой (например, сохранять изображения)
- Отправлять письма и делать всё, что нельзя (и не должно) делать на клиенте
Пример:
'use server'
import { db } from './db';
export async function createUser(formData) {
const name = formData.get('name');
await db.users.insert({ name });
}
Server Actions и безопасность
Server Actions всегда выполняются на сервере. Это значит:
- Ваши секреты (ключи, пароли, доступ к базе) не попадут на клиент.
- Вы не можете случайно "утянуть" логику на клиент — Next.js вас защитит.
Однако:
Всё, что приходит от пользователя (даже через Server Action), нужно валидировать и проверять на сервере! Не доверяйте данным из формы, даже если они пришли через "безопасную" Server Action.
6. Типичные ошибки при создании Server Actions
Ошибка №1: забыли директиву "use server"
Без этой строки функция не станет Server Action, а Next.js не сможет её вызвать с клиента. Всегда проверяйте, что директива стоит первой строкой.
Ошибка №2: попытка использовать Server Action в Client Component
Server Actions можно вызывать только из Server Component или из форм, объявленных в серверных компонентах. Если попробуете импортировать Server Action в компонент с "use client", получите ошибку сборки.
Ошибка №3: обращение к полям FormData как к обычному объекту
FormData — не обычный объект! Используйте .get('name') для получения значения.
Ошибка №4: забыли сделать функцию async
Server Action должна быть асинхронной (async). Если забыли — получите ошибку или странное поведение.
Ошибка №5: невалидированные данные
Никогда не доверяйте данным из формы. Даже если Server Action выполняется на сервере, проверяйте и валидируйте всё, что приходит от пользователя.
Ошибка №6: попытка вернуть сложные объекты
Server Actions могут возвращать только сериализуемые данные (числа, строки, простые объекты). Нельзя возвращать, например, функции или нестандартные объекты.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ