useActionState

useActionState 是一個 Hook,允許您根據表單動作的結果更新狀態。

const [state, formAction, isPending] = useActionState(fn, initialState, permalink?);

注意事項

在較早的 React Canary 版本中,此 API 是 React DOM 的一部分,並稱為 useFormState


參考

useActionState(action, initialState, permalink?)

在組件的頂層呼叫 useActionState 來創建在 調用表單動作時 更新的組件狀態。您傳遞給 useActionState 一個現有的表單動作函式以及初始狀態,它會返回一個您在表單中使用的新的動作,以及最新的表單狀態和動作是否仍在處理中。最新的表單狀態也會傳遞給您提供的函式。

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:您希望狀態最初的值。它可以是任何可序列化的值。第一次調用動作後,將忽略此參數。
  • 選用 permalink:包含此表單修改的唯一頁面 URL 的字串。用於具有動態內容(例如:feed)的頁面,並與漸進增強一起使用:如果 fn 是一個 伺服器函式 且在 JavaScript 捆綁包載入之前提交了表單,瀏覽器將導航到指定的 permalink URL,而不是當前頁面的 URL。確保在目標頁面上呈現相同的表單組件(包括相同的動作 fnpermalink),以便 React 知道如何傳遞狀態。一旦表單被水合,此參數將不起作用。

回傳值

useActionState 返回一個包含以下值的陣列

  1. 目前的狀態。在第一次渲染期間,它將與您傳遞的 initialState 相符。調用動作後,它將與動作返回的值相符。
  2. 您可以將一個新的動作作為 action prop 傳遞給您的 form 元件,或者作為 formAction prop 傳遞給表單內任何的 button 元件。
  3. isPending 旗標會告訴您是否有正在處理中的 Transition(轉換)。

注意事項

  • 當與支援 React 伺服器元件的框架一起使用時,useActionState 允許您在客戶端執行 JavaScript 之前使表單具有互動性。如果不使用伺服器元件,它等同於元件的局部狀態。
  • 傳遞給 useActionState 的函式會接收一個額外的參數,即先前的或初始的狀態,作為它的第一個參數。這使得它的簽名與直接用作表單動作而不使用 useActionState 時不同。

用法

使用表單動作返回的資訊

在元件的最上層呼叫 useActionState 來存取上次提交表單時動作的返回值。

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. 一個新的動作,您將其作為 action prop 傳遞給 <form>
  3. 一個pending 狀態,您可以在動作處理時使用它。

當提交表單時,您提供的動作函式將被呼叫。它的返回值將成為表單新的目前狀態

您提供的動作也會收到一個新的第一個參數,即表單的目前狀態。第一次提交表單時,這將是您提供的初始狀態,而在後續提交中,它將是上次呼叫動作時的返回值。其餘的參數與未使用 useActionState 時相同。

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

提交表單後顯示資訊

範例 1 2:
顯示表單錯誤

要顯示伺服器函式返回的訊息,例如錯誤訊息或toast,請將動作包裝在對 useActionState 的呼叫中。

import { useActionState, useState } from "react";
import { addToCart } from "./actions.js";

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

export default function App() {
  return (
    <>
      <AddToCartForm itemID="1" itemTitle="JavaScript: The Definitive Guide" />
      <AddToCartForm itemID="2" itemTitle="JavaScript: The Good Parts" />
    </>
  )
}

疑難排解

我的動作無法再讀取提交的表單數據

當您使用 useActionState 包裝動作時,它會獲得一個額外的參數,*作為它的第一個參數*。因此,提交的表單數據是它的*第二個*參數,而不是像通常那樣是第一個參數。新增的第一個參數是表單的目前狀態。

function action(currentState, formData) {
// ...
}