サーバアクション
サーバアクション (Server Action) を使用することで、サーバで実行される非同期関数をクライアントコンポーネントから呼び出すことができます。
- サーバコンポーネントからサーバアクションを作成する
- クライアントコンポーネントからサーバアクションをインポートする
- アクションとサーバアクションを組み合わせる
- フォームアクションとサーバアクション
useActionState
とサーバアクションuseActionState
を使用したプログレッシブエンハンスメント
サーバアクションが "use server"
ディレクティブを付けて定義されると、フレームワークは自動的にそのサーバ関数への参照を作成し、その参照をクライアントコンポーネントに渡します。クライアントでこの関数が呼び出されると、React はサーバにリクエストを送信して元の関数を実行し、その結果を返します。
サーバアクションはサーバコンポーネント内で作成し、クライアントコンポーネントに props として渡すことができます。また、クライアントコンポーネントで直接インポートして使用することも可能です。
サーバコンポーネントからサーバアクションを作成する
サーバコンポーネントは "use server"
ディレクティブを使用してサーバアクションを定義できます。
// Server Component
import Button from './Button';
function EmptyNote () {
async function createNoteAction() {
// Server Action
'use server';
await db.notes.create();
}
return <Button onClick={createNoteAction}/>;
}
React がサーバコンポーネントである EmptyNote
をレンダーすると、createNoteAction
関数への参照を作成し、この参照をクライアントコンポーネントである Button
に渡します。ボタンがクリックされると、React は渡された参照を使用してサーバにリクエストを送信し、createNoteAction
関数を実行します。
"use client";
export default function Button({onClick}) {
console.log(onClick);
// {$$typeof: Symbol.for("react.server.reference"), $$id: 'createNoteAction'}
return <button onClick={() => onClick()}>Create Empty Note</button>
}
詳細については、"use server"
のドキュメントを参照してください。
クライアントコンポーネントからサーバアクションをインポートする
クライアントコンポーネントは "use server"
ディレクティブを使用するファイルから、サーバアクションをインポートできます。
"use server";
export async function createNoteAction() {
await db.notes.create();
}
バンドラがクライアントコンポーネントである EmptyNote
をビルドする際に、バンドル内で createNoteAction
関数への参照を作成します。button
がクリックされると、React は渡された参照を使用してサーバにリクエストを送信し、createNoteAction
関数を実行します。
"use client";
import {createNoteAction} from './actions';
function EmptyNote() {
console.log(createNoteAction);
// {$$typeof: Symbol.for("react.server.reference"), $$id: 'createNoteAction'}
return <button onClick={createNoteAction} />
}
詳細については、"use server"
のドキュメントを参照してください。
アクションとサーバアクションを組み合わせる
サーバアクションはクライアントのアクションと組み合わせることができます。
"use server";
export async function updateName(name) {
if (!name) {
return {error: 'Name is required'};
}
await db.users.updateName(name);
}
"use client";
import {updateName} from './actions';
function UpdateName() {
const [name, setName] = useState('');
const [error, setError] = useState(null);
const [isPending, startTransition] = useTransition();
const submitAction = async () => {
startTransition(async () => {
const {error} = await updateName(name);
if (!error) {
setError(error);
} else {
setName('');
}
})
}
return (
<form action={submitAction}>
<input type="text" name="name" disabled={isPending}/>
{state.error && <span>Failed: {state.error}</span>}
</form>
)
}
このようにクライアント側のアクションでラップすることで、サーバアクションによる isPending
state にアクセスできます。
詳細については、フォーム外でサーバアクションを呼び出すを参照してください。
フォームアクションとサーバアクション
サーバアクションは React 19 の新しいフォーム関連機能と連携します。
フォームにサーバアクションを渡すことで、自動的にフォームをサーバに送信できます。
"use client";
import {updateName} from './actions';
function UpdateName() {
return (
<form action={updateName}>
<input type="text" name="name" />
</form>
)
}
フォームの送信が成功すると、React は自動的にフォームをリセットします。useActionState
を追加して、進行中 (pending) state や最終的なレスポンスにアクセスしたり、プログレッシブエンハンスメント (progressive enhancement) をサポートしたりすることが可能です。
詳細については、フォーム内でのサーバアクションを参照してください。
useActionState
とサーバアクション
useActionState
とサーバアクションを組み合わせることで、アクションの進行中 state と最後に返されたレスポンスにアクセスする、という一般的なユースケースに対応できます。
"use client";
import {updateName} from './actions';
function UpdateName() {
const [state, submitAction, isPending] = useActionState(updateName, {error: null});
return (
<form action={submitAction}>
<input type="text" name="name" disabled={isPending}/>
{state.error && <span>Failed: {state.error}</span>}
</form>
);
}
サーバアクションと useActionState
を使用する場合、React はハイドレーションの完了前に実行されたフォーム送信を自動的に再現します。これにより、ユーザはアプリのハイドレーションが起きる前からアプリを操作できるようになります。
詳細については、useActionState
のドキュメントを参照してください。
useActionState
を使用したプログレッシブエンハンスメント
サーバアクションは useActionState
の第 3 引数を使用してプログレッシブエンハンスメントもサポートします。
"use client";
import {updateName} from './actions';
function UpdateName() {
const [, submitAction] = useActionState(updateName, null, `/name/update`);
return (
<form action={submitAction}>
...
</form>
);
}
パーマリンクが useActionState
に渡された場合、JavaScript バンドルが読み込まれる前にフォームが送信されると、React はこの渡された URL にリダイレクトします。
詳しくは、useActionState
のドキュメントを参照してください。