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

'use server'

'use server' отмечает функции стороны сервера, которые могут быть вызваны из кода стороны клиента.

'use server' нужен при использовании серверных компонентов React.

Описание

'use server'

Добавьте 'use server' в верхней части тела async-функции, чтобы пометить функцию как вызываемую клиентом. Такие функции называют серверными функциями.

1
2
3
4
async function addToCart(data) {
    'use server';
    // ...
}

При вызове серверной функции на клиенте выполняется сетевой запрос к серверу, включающий сериализованную копию всех переданных аргументов. Если серверная функция возвращает значение, оно будет сериализовано и возвращено клиенту.

Вместо того чтобы отдельно отмечать функции директивой 'use server', можно добавить директиву в верхнюю часть файла. Тогда все экспорты этого файла станут серверными функциями и их можно использовать где угодно, в том числе импортировать в клиентский код.

Замечания

  • Директивы 'use server' должны находиться в самом начале своей функции или модуля; выше любого другого кода, включая импорт (комментарии над директивами - это нормально). Они должны быть написаны с одинарными или двойными кавычками, а не с обратными знаками.
  • Директива 'use server' может быть использована только в файлах серверной части. Получившиеся серверные функции можно передавать клиентским компонентам через пропсы. Смотрите поддерживаемые типы для сериализации.
  • Чтобы импортировать серверную функцию из кода клиента, необходимо использовать директиву на уровне модуля.
  • Поскольку базовые сетевые вызовы всегда асинхронны, 'use server' можно использовать только в асинхронных функциях.
  • Всегда рассматривайте аргументы серверных функций как недоверенный ввод и авторизуйте любые мутации. Смотрите соображения безопасности.
  • Серверные функции нужно вызывать в переходе. Серверные функции, переданные в <form action> или formAction, вызываются в переходе автоматически.
  • Серверные функции предназначены для мутаций, которые обновляют состояние на стороне сервера; их не рекомендуется использовать для получения данных. Соответственно, фреймворки, реализующие серверные функции, обычно обрабатывают одно действие за раз и не кэшируют возвращаемое значение.

Соображения безопасности

Аргументы серверных функций полностью контролируются клиентом. В целях безопасности всегда рассматривайте их как недоверенный ввод и обязательно проверяйте и экранируйте аргументы.

В любой серверной функции обязательно проверяйте, что вошедшему в систему пользователю разрешено выполнять это действие.

В разработке

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

См. experimental_taintUniqueValue и experimental_taintObjectReference.

Сериализуемые аргументы и возвращаемые значения

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

Здесь перечислены поддерживаемые типы аргументов серверной функции:

Примечательно, что не поддерживаются:

  • React-элементы или JSX
  • Функции, включая функции компонентов или любые другие функции, которые не являются действиями сервера
  • Classes
  • Объекты, являющиеся экземплярами любого класса (кроме упомянутых встроенных) или объекты с нулевым прототипом
  • Символы, не зарегистрированные глобально, например, Symbol('mySymbol').
  • События из обработчиков событий

Поддерживаемые сериализуемые возвращаемые значения такие же, как сериализуемые реквизиты для граничного клиентского компонента.

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

Серверные функции в формах

Чаще всего серверные функции вызывают, чтобы изменить данные. В браузере традиционный способ отправить мутацию — элемент HTML-формы. В React Server Components у серверных функций есть первоклассная поддержка как у действий в формах.

Вот форма, в которой пользователь может запросить имя пользователя.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// App.js

async function requestUsername(formData) {
  'use server';
  const username = formData.get('username');
  // ...
}

export default function App() {
  return (
    <form action={requestUsername}>
      <input type="text" name="username" />
      <button type="submit">Request</button>
    </form>
  );
}

В этом примере requestUsername — серверная функция, переданная в <form>. Когда пользователь отправляет форму, уходит сетевой запрос к серверной функции requestUsername. При вызове серверной функции из формы React передаёт FormData формы первым аргументом серверной функции.

Если передать серверную функцию в action формы, React может прогрессивно улучшить форму. Это значит, что форму можно отправить ещё до загрузки пакета JavaScript.

Обработка возвращаемых значений в формах

В форме запроса имени имя может оказаться занятым. requestUsername должна сообщить, удался запрос или нет.

Чтобы обновить интерфейс по результату серверной функции и при этом сохранить прогрессивное улучшение, используйте useActionState.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// requestUsername.js
'use server';

export default async function requestUsername(formData) {
  const username = formData.get('username');
  if (canRequest(username)) {
    // ...
    return 'successful';
  }
  return 'failed';
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// UsernameForm.js
'use client';

import { useActionState } from 'react';
import requestUsername from './requestUsername';

function UsernameForm() {
  const [state, action] = useActionState(requestUsername, null, 'n/a');

  return (
    <>
      <form action={action}>
        <input type="text" name="username" />
        <button type="submit">Request</button>
      </form>
      <p>Last submission request returned: {state}</p>
    </>
  );
}

Как и большинство хуков, useActionState можно вызывать только в клиентском коде.

Вызов серверной функции вне <form>

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

Если серверная функция используется вне формы, вызывайте её в переходе: так можно показать индикатор загрузки, оптимистичные обновления состояния и обработать неожиданные ошибки. Формы автоматически оборачивают серверные функции в переходы.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import incrementLike from './actions';
import { useState, useTransition } from 'react';

function LikeButton() {
  const [isPending, startTransition] = useTransition();
  const [likeCount, setLikeCount] = useState(0);

  const onClick = () => {
    startTransition(async () => {
      const currentCount = await incrementLike();
      startTransition(() => {
        setLikeCount(currentCount);
      });
    });
  };

  return (
    <>
      <p>Total Likes: {likeCount}</p>
      <button onClick={onClick} disabled={isPending}>Like</button>;
    </>
  );
}
1
2
3
4
5
6
7
8
// actions.js
'use server';

let likeCount = 0;
export default async function incrementLike() {
  likeCount++;
  return likeCount;
}

Чтобы прочитать возвращаемое значение серверной функции, нужно сделать await у возвращённого промиса.

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

Комментарии