useActionState
useActionState
は、フォームアクションの結果に基づいて state を更新するためのフックです。
const [state, formAction, isPending] = useActionState(fn, initialState, permalink?);
リファレンス
useActionState(action, initialState, permalink?)
コンポーネントのトップレベルで useActionState
を呼び出してコンポーネントの state を作成し、フォームアクションが呼び出されたときに更新されるようにします。既存のフォームアクション関数と初期 state を useActionState
に渡し、フォームで使用する新しいアクションと最新のフォーム state、およびアクションの進行状況が返されます。あなたが渡した関数にも、最新のフォーム state が渡されるようになります。
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>
)
}
フォーム state とは、フォームが最後に送信されたときにアクションによって返される値です。フォームがまだ送信されていない場合は、渡された初期 state が使われます。
サーバアクションと併用して useActionState
を使うことで、ハイドレーションが完了する前にフォームが送信された場合でも、そのサーバからのレスポンスを表示できるようになります。
引数
fn
: フォームが送信されたりボタンが押されたりしたときに呼び出される関数。この関数が呼び出される際には、1 番目の引数としてはフォームの前回 state(初回は渡したinitialState
、2 回目以降は前回の返り値)を受け取り、次の引数としてはフォームアクションが通常受け取る引数を受け取ります。initialState
: state の初期値として使いたい値。シリアライズ可能な任意の値です。この引数はアクションが一度呼び出された後は無視されます。- 省略可能
permalink
: このフォームが書き換えの対象とするユニークなページ URL を含んだ文字列。ダイナミックなコンテンツ(ページフィードなど)のあるページでプログレッシブエンハンスメントを組み合わせる場合に使用します。fn
がサーバアクションであり、かつフォームが JavaScript バンドルの読み込み完了前に送信された場合、ブラウザは現在のページ URL ではなくこの指定されたパーマリンク用 URL に移動するようになります。React が state を正しく受け渡せるよう、移動先となるページでも(アクションfn
とpermalink
も含む)同じフォームが必ずレンダーされるようにしてください。フォームのハイドレーションが完了した後は、このパラメータは無視されます。
返り値
useActionState
は以下の値を含む配列を返します。
- 現在の state。初回レンダー時には、渡した
initialState
と等しくなります。アクションが呼び出された後は、そのアクションが返した値と等しくなります。 - フォームコンポーネントの
action
プロパティや、フォーム内の任意のbutton
コンポーネントのformAction
プロパティとして渡すことができる新しいアクション。 - 進行中のトランジションがあるかどうかを表す
isPending
フラグ。
注意点
- React Server Components をサポートするフレームワークで使用する場合、
useActionState
はクライアント上で JavaScript が実行される前にフォームを操作可能にできます。Server Components なしで使用する場合、コンポーネントのローカル state と同様のものになります。 useActionState
に渡される関数は、追加の 1 番目の引数として、前回 state ないし初期 state を受け取ります。従って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
は、以下の項目を含む配列を返します。
- フォームの state の現在値。初期値はあなたが渡した 初期 state となり、フォームが送信された後はあなたが渡したアクションの返り値となります。
<form>
の props であるaction
に渡せる新しいアクション。- アクションが処理中かどうかを知るのに利用できる pending 状態。
フォームが送信されると、あなたが渡したアクション関数が呼び出されます。その返り値が、新たなフォームの state 現在値になります。
あなたが渡すアクションは、新たな第 1 引数として、フォームのstate の現在値を受け取ります。フォームが初めて送信されるとき、これはあなたが渡した初期 state と等しくなります。次回以降の送信では、アクションが前回呼び出されたときの返り値になります。残りの引数は useActionState
を使用しなかった場合と同じです。
function action(currentState, formData) {
// ...
return 'next state';
}
例 1/2: フォームエラーの表示
サーバアクションによって返されるメッセージをエラーメッセージやトーストとして表示するには、そのアクションを 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" /> </> ) }