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

'use server'

Canary

'use server' необходимо только в том случае, если вы используете React Server Components или собираете совместимую с ними библиотеку.

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

Описание

'use server'

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

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

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

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

Замечания

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

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

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

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

В разработке

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

См. experimental_taintUniqueValue и experimental_taintObjectReference.

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

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

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

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

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

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

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

Действия сервера в формах

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

Здесь представлена форма, позволяющая пользователю запросить имя пользователя.

 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
20
21
22
23
24
25
// UsernameForm.js
'use client';

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

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

    return (
        <>
            <form action={action}>
                <input type="text" name="username" />
                <button type="submit">Request</button>
            </form>
            <p>
                Last submission request returned:{' '}
                {returnValue}
            </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();
            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

Комментарии