Перейти к содержанию

Серверные функции

Серверные функции позволяют клиентским компонентам вызывать асинхронные функции, которые выполняются на сервере.

Серверные функции предназначены для серверных компонентов React.

Примечание: до сентября 2024 года все серверные функции назывались «Server Actions». Если серверная функция передана в проп action или вызвана изнутри действия, это серверное действие (Server Action), но не все серверные функции являются серверными действиями. Названия в этой документации обновлены: серверные функции можно использовать для разных задач.

Как обеспечить поддержку серверных функций?

Хотя серверные функции в React 19 стабильны и не будут ломаться между минорными версиями, базовые API, которыми бандлер или фреймворк React Server Components реализует серверные функции, не следуют semver и могут ломаться между минорными версиями React 19.x.

Чтобы поддерживать серверные функции в бандлере или фреймворке, рекомендуем зафиксировать конкретную версию React или использовать релиз Canary. Мы продолжим работать с авторами бандлеров и фреймворков, чтобы в будущем стабилизировать API для реализации серверных функций.

Когда серверная функция объявлена с директивой "use server", фреймворк автоматически создаст ссылку на серверную функцию и передаст эту ссылку клиентскому компоненту. Когда функцию вызовут на клиенте, React отправит запрос на сервер, чтобы выполнить функцию, и вернёт результат.

Серверные функции можно создавать в серверных компонентах и передавать пропсами клиентским компонентам, либо импортировать и использовать в клиентских компонентах.

Использование

Создание серверной функции в серверном компоненте

Серверные компоненты могут объявлять серверные функции директивой "use server":

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// Server Component
import Button from './Button';

function EmptyNote () {
  async function createNoteAction() {
    // Server Function
    'use server';

    await db.notes.create();
  }

  return <Button onClick={createNoteAction}/>;
}

Когда React рендерит серверный компонент EmptyNote, он создаёт ссылку на функцию createNoteAction и передаёт эту ссылку клиентскому компоненту Button. Когда кнопку нажмут, React отправит запрос на сервер, чтобы выполнить функцию createNoteAction по переданной ссылке:

1
2
3
4
5
6
7
"use client";

export default function Button({onClick}) {
  console.log(onClick);
  // {$$typeof: Symbol.for("react.server.reference"), $$id: 'createNoteAction'}
  return <button onClick={() => onClick()}>Create Empty Note</button>
}

Подробнее см. документацию по "use server".

Импорт серверных функций из клиентских компонентов

Клиентские компоненты могут импортировать серверные функции из файлов с директивой "use server":

1
2
3
4
5
"use server";

export async function createNote() {
  await db.notes.create();
}

Когда бандлер собирает клиентский компонент EmptyNote, он создаёт в бандле ссылку на функцию createNote. Когда нажмут button, React отправит запрос на сервер, чтобы выполнить функцию createNote по переданной ссылке:

1
2
3
4
5
6
7
8
"use client";
import {createNote} from './actions';

function EmptyNote() {
  console.log(createNote);
  // {$$typeof: Symbol.for("react.server.reference"), $$id: 'createNote'}
  <button onClick={() => createNote()} />
}

Подробнее см. документацию по "use server".

Серверные функции с действиями

Серверные функции можно вызывать из действий на клиенте:

1
2
3
4
5
6
7
8
"use server";

export async function updateName(name) {
  if (!name) {
    return {error: 'Name is required'};
  }
  await db.users.updateName(name);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
"use client";

import {updateName} from './actions';

function UpdateName() {
  const [name, setName] = useState('');
  const [error, setError] = useState(null);

  const [isPending, startTransition] = useTransition();

  const submitAction = async () => {
    startTransition(async () => {
      const {error} = await updateName(name);
      startTransition(() => {
        if (error) {
          setError(error);
        } else {
          setName('');
        }
      });
    })
  }

  return (
    <form action={submitAction}>
      <input type="text" name="name" disabled={isPending}/>
      {error && <span>Failed: {error}</span>}
    </form>
  )
}

Так можно получить состояние isPending серверной функции, обернув её в действие на клиенте.

Подробнее см. документацию Вызов серверной функции вне <form>

Серверные функции с действиями формы

Серверные функции работают с новыми возможностями форм в React 19.

Серверную функцию можно передать форме, чтобы форма автоматически отправлялась на сервер:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
"use client";

import {updateName} from './actions';

function UpdateName() {
  return (
    <form action={updateName}>
      <input type="text" name="name" />
    </form>
  )
}

Если отправка формы прошла успешно, React автоматически сбросит форму. Добавьте useActionState, чтобы получить состояние ожидания, последний ответ или поддержать прогрессивное улучшение.

Подробнее см. документацию Серверные функции в формах.

Серверные функции с useActionState

Серверные функции можно вызывать через useActionState в типичном случае, когда нужны только состояние ожидания действия и последний возвращённый ответ:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
"use client";

import {updateName} from './actions';

function UpdateName() {
  const [state, submitAction, isPending] = useActionState(updateName, {error: null});

  return (
    <form action={submitAction}>
      <input type="text" name="name" disabled={isPending}/>
      {state.error && <span>Failed: {state.error}</span>}
    </form>
  );
}

Если useActionState используется вместе с серверными функциями, React также автоматически повторит отправки формы, сделанные до окончания гидратации. Пользователи смогут взаимодействовать с приложением ещё до того, как оно гидратируется.

Подробнее см. документацию useActionState.

Прогрессивное улучшение с useActionState

Серверные функции также поддерживают прогрессивное улучшение через третий аргумент useActionState.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
"use client";

import {updateName} from './actions';

function UpdateName() {
  const [, submitAction] = useActionState(updateName, null, `/name/update`);

  return (
    <form action={submitAction}>
      ...
    </form>
  );
}

Если в useActionState передана постоянная ссылка, React перенаправит на указанный URL, когда форма отправлена до загрузки бандла JavaScript.

Подробнее см. документацию useActionState.

Источник — https://react.dev/reference/rsc/server-functions

Комментарии