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

useActionState

Canary

Хук useActionState в настоящее время доступен только в канале React canary и experimental. Подробнее о каналах выпуска здесь. Кроме того, для получения всех преимуществ useActionState вам необходимо использовать фреймворк, поддерживающий React Server Components.

В более ранних версиях React Canary этот API был частью React DOM и назывался useFormState.

useActionState - это хук, который позволяет вам обновлять состояние на основе результата действия формы.

1
2
3
4
const [state, formAction] = useActionState(
    fn,
    initialState
);

Описание

useActionState(action, initialState)

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import { useActionState } from 'react';

async function increment(previousState, formData) {
    return previousState + 1;
}

function StatefulForm({}) {
    const [state, formAction] = useActionState(
        increment,
        0
    );
    return (
        <form>
            {state}
            <button formAction={formAction}>
                Increment
            </button>
        </form>
    );
}

Состояние формы - это значение, возвращенное действием, когда форма была отправлена в последний раз. Если форма еще не была отправлена, это начальное состояние, которое вы передаете.

При использовании с серверным действием useActionState позволяет показывать ответ сервера от отправки формы даже до завершения гидратации.

Параметры

  • fn: Функция, которая будет вызываться при отправке формы или нажатии кнопки. Когда функция вызывается, она получает предыдущее состояние формы (сначала initialState, которое вы передаете, а затем предыдущее возвращаемое значение) в качестве начального аргумента, а затем аргументы, которые обычно получает действие формы.
  • initialState: Значение, которое вы хотите получить в качестве начального состояния. Это может быть любое сериализуемое значение. Этот аргумент игнорируется после первого вызова действия.

Возвращаемое значение

useActionState возвращает массив, содержащий ровно два значения:

  1. Текущее состояние. Во время первого рендера оно будет соответствовать переданному вами значению initialState. После вызова действия оно будет соответствовать значению, возвращенному действием.
  2. Новое действие, которое вы можете передать в качестве свойства action компоненту form или свойства formAction любому компоненту button внутри формы.

Ограничения

  • При использовании с фреймворком, поддерживающим серверные компоненты React, useActionState позволяет сделать формы интерактивными до выполнения JavaScript на клиенте. При использовании без серверных компонентов это эквивалентно локальному состоянию компонента.
  • Функция, передаваемая useActionState, получает в качестве первого аргумента дополнительный аргумент - предыдущее или начальное состояние. Это делает ее сигнатуру иной, чем если бы она использовалась непосредственно как действие формы без использования useActionState.

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

Использование информации, возвращаемой действием формы

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import { useActionState } from 'react';
import { action } from './actions.js';

function MyComponent() {
    const [state, formAction] = useActionState(
        action,
        null
    );
    // ...
    return <form action={formAction}>{/* ... */}</form>;
}

useActionState возвращает массив, содержащий ровно два элемента:

  1. Текущее состояние формы, которое первоначально устанавливается в указанное вами начальное состояние, а после отправки формы устанавливается в возвращаемое значение указанного вами действия.
  2. Новое действие, которое вы передаете в <form> в качестве его свойства action.

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

Предоставленное вами действие также получит новый первый аргумент, а именно текущее состояние формы. При первой отправке формы это будет начальное состояние, которое вы указали, а при последующих отправках - возвращаемое значение, полученное при последнем вызове действия. Остальные аргументы такие же, как если бы useActionState не использовался

1
2
3
4
function action(currentState, formData) {
    // ...
    return 'next state';
}

Отображение информации после отправки формы

1. Отображение ошибок формы

Чтобы отобразить сообщения, такие как сообщение об ошибке или тост, возвращаемый серверным действием, оберните действие вызовом useActionState.

 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
31
32
33
34
35
36
37
import { useState } from 'react';
import { useActionState } from 'react';
import { addToCart } from './actions.js';

function AddToCartForm({ itemID, itemTitle }) {
    const [message, formAction] = useActionState(
        addToCart,
        null
    );
    return (
        <form action={formAction}>
            <h2>{itemTitle}</h2>
            <input
                type="hidden"
                name="itemID"
                value={itemID}
            />
            <button type="submit">Add to Cart</button>
            {message}
        </form>
    );
}

export default function App() {
    return (
        <>
            <AddToCartForm
                itemID="1"
                itemTitle="JavaScript: The Definitive Guide"
            />
            <AddToCartForm
                itemID="2"
                itemTitle="JavaScript: The Good Parts"
            />
        </>
    );
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
'use server';

export async function addToCart(prevState, queryData) {
    const itemID = queryData.get('itemID');
    if (itemID === '1') {
        return 'Added to cart';
    } else {
        return "Couldn't add to cart: the item is sold out.";
    }
}

2. Отображение структурированной информации после отправки формы

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

 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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import { useState } from 'react';
import { useActionState } from 'react';
import { addToCart } from './actions.js';

function AddToCartForm({ itemID, itemTitle }) {
    const [formState, formAction] = useActionState(
        addToCart,
        {}
    );
    return (
        <form action={formAction}>
            <h2>{itemTitle}</h2>
            <input
                type="hidden"
                name="itemID"
                value={itemID}
            />
            <button type="submit">Add to Cart</button>
            {formState?.success && (
                <div className="toast">
                    Added to cart! Your cart now has{' '}
                    {formState.cartSize} items.
                </div>
            )}
            {formState?.success === false && (
                <div className="error">
                    Failed to add to cart:{' '}
                    {formState.message}
                </div>
            )}
        </form>
    );
}

export default function App() {
    return (
        <>
            <AddToCartForm
                itemID="1"
                itemTitle="JavaScript: The Definitive Guide"
            />
            <AddToCartForm
                itemID="2"
                itemTitle="JavaScript: The Good Parts"
            />
        </>
    );
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
'use server';

export async function addToCart(prevState, queryData) {
    const itemID = queryData.get('itemID');
    if (itemID === '1') {
        return {
            success: true,
            cartSize: 12,
        };
    } else {
        return {
            success: false,
            message: 'The item is sold out.',
        };
    }
}

Решение проблем

Мое действие больше не может читать данные отправленной формы

Когда вы оборачиваете действие с помощью useActionState, оно получает дополнительный аргумент в качестве первого аргумента. Таким образом, отправленные данные формы являются его вторым аргументом, а не первым, как это было бы обычно. Новый первый аргумент, который добавляется, - это текущее состояние формы.

1
2
3
function action(currentState, formData) {
    // ...
}

Источник — https://react.dev/reference/react/useActionState

Комментарии