React Server Actions: как заменить API endpoints на прямые вызовы серверных функций

#react#react19#server-components

image: “https://media2.dev.to/dynamic/image/width=1200,height=627,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdrogrsknm00cerv5a9pu.png” pubDate: 2026-07-17T12:28:51.073Z

Когда последний раз вам приходилось писать очередной /api/submit-form эндпоинт только для того, чтобы сохранить данные из простой формы? React 19 предлагает альтернативу — Server Actions, которые позволяют вызывать серверные функции прямо из клиентских компонентов. Но работает ли это в реальных проектах или это очередной overhyped feature?

От API endpoints к Server Actions: что изменилось

Традиционный флоу работы с формами в React выглядит так:

  1. Клиентский компонент собирает данные
  2. Отправляет их через fetch или axios на API route
  3. Обрабатывает loading/error/success состояния
  4. Обновляет UI после ответа

С Server Actions схема становится проще:

// Клиентский компонент
<form action={serverAction}>
  {/* поля формы */}
</form>

// Серверная функция
"use server"
export async function serverAction(formData) {
  // работа с БД прямо здесь
}

На практике это означает, что:

Но есть и нюансы: например, нельзя просто передать произвольные данные — только то, что сериализуется в JSON. Это значит, что классы, функции или циклические ссылки вызовут ошибки.

Как это работает в продакшне: разбираем кейс

Допустим, у нас есть Next.js-приложение с формой добавления товара. Вот как выглядит реализация с Server Actions:

// actions/product.ts
"use server"

import { db } from "./db"

export async function addProduct(prevState: any, formData: FormData) {
  const name = formData.get("name")
  const price = formData.get("price")
  
  // Валидация
  if (!name || name.length < 3) {
    return { error: "Name must be at least 3 chars" }
  }

  try {
    const product = await db.products.create({ 
      data: { name, price: Number(price) }
    })
    return { success: true, product }
  } catch (err) {
    return { error: "Failed to create product" }
  }
}

Клиентская часть:

// components/AddProductForm.tsx
"use client"

import { useActionState } from "react"
import { addProduct } from "@/actions/product"

export function AddProductForm() {
  const [state, action, isPending] = useActionState(addProduct, null)
  
  return (
    <form action={action}>
      <input name="name" />
      <input name="price" type="number" />
      <button disabled={isPending}>
        {isPending ? "Saving..." : "Add Product"}
      </button>
      {state?.error && <div className="error">{state.error}</div>}
    </form>
  )
}

Что здесь важно:

  1. Серверный код изолирован — он никогда не попадает в клиентский бандл
  2. useActionState автоматически обрабатывает pending состояния
  3. Форма остается интерактивной даже без JavaScript (progressive enhancement)

Когда Server Actions — не лучший выбор

Несмотря на удобство, есть сценарии, где Server Actions могут усложнить архитектуру:

В таких случаях традиционные API endpoints все еще выигрывают.

Что попробовать в следующих проектах

  1. Комбинируйте Server Actions с useOptimistic для мгновенного UI-ответа
  2. Добавьте Zod для валидации данных на сервере
  3. Поэкспериментируйте с прогрессивным улучшением — отключите JavaScript и проверьте, как работает форма

Server Actions — это не серебряная пуля, но для многих CRUD-операций они действительно сокращают бойлерплейт. Главное — не пытаться запихнуть в них всю бизнес-логику и помнить про ограничения сериализации.


Источник: https://dev.to/banti_kevat_8e2d123bb7994/react-server-actions-complete-guide-react-19-in-hindi-4k9l