'use server'
は、クライアントサイドコードから呼び出すことができるサーバーサイド関数をマークします。
リファレンス
'use server'
非同期関数の本体の先頭に'use server'
を追加して、クライアントから呼び出し可能な関数としてマークします。これらの関数をサーバー関数と呼びます。
async function addToCart(data) {
'use server';
// ...
}
クライアントでサーバー関数を呼び出すと、渡された引数のシリアライズされたコピーを含むサーバーへのネットワークリクエストが行われます。サーバー関数が値を返す場合、その値はシリアライズされてクライアントに返されます。
関数を個別に'use server'
でマークする代わりに、ファイルの先頭にディレクティブを追加して、そのファイル内のすべてのエクスポートを、クライアントコードでインポートされるなど、どこでも使用できるサーバー関数としてマークすることができます。
注意点
'use server'
は、関数の先頭、またはモジュールの先頭になければなりません。インポートなどの他のコードより上に置く必要があります(ディレクティブの上のコメントはOKです)。シングルまたはダブルクォートで記述する必要があり、バッククォートは使用できません。'use server'
は、サーバーサイドファイルでのみ使用できます。結果として得られるサーバー関数は、プロップを通してクライアントコンポーネントに渡すことができます。シリアライズ可能な型を参照してください。- クライアントコードからサーバー関数をインポートするには、モジュールレベルでディレクティブを使用する必要があります。
- 基礎となるネットワーク呼び出しは常に非同期であるため、
'use server'
は非同期関数でのみ使用できます。 - サーバー関数の引数は常に信頼できない入力として扱い、すべての変更を承認してください。セキュリティに関する考慮事項を参照してください。
- サーバー関数は、サーバーサイドの状態を更新する変更用に設計されています。データの取得には推奨されません。したがって、サーバー関数を実装するフレームワークは通常、一度に1つのアクションを処理し、戻り値をキャッシュする方法がありません。
- サーバー関数は、トランジション内で呼び出す必要があります。
<form action>
またはformAction
に渡されるサーバー関数は、自動的にトランジション内で呼び出されます。
セキュリティに関する考慮事項
サーバー関数の引数は、完全にクライアントによって制御されます。セキュリティのために、常に信頼できない入力として扱い、必要に応じて引数を検証してエスケープしてください。
すべてのサーバー関数で、ログインしているユーザーがそのアクションを実行することを許可されていることを検証してください。
シリアライズ可能な引数と戻り値
クライアントコードはネットワーク経由でサーバー関数呼び出すため、渡される引数はすべてシリアライズ可能である必要があります。
サーバー関数の引数としてサポートされる型を以下に示します。
- プリミティブ型
- シリアライズ可能な値を含む反復可能オブジェクト
- Date
- FormData インスタンス
- プレーンオブジェクト:オブジェクト初期化子で作成され、シリアライズ可能なプロパティを持つオブジェクト
- サーバー関数である関数
- Promises
特に、これらはサポートされていません。
- React 要素、または JSX
- 関数(コンポーネント関数またはサーバー関数以外の任意の関数を含む)
- クラス
- 任意のクラス(前述の組み込み型を除く)のインスタンスであるオブジェクト、またはプロトタイプがnullのオブジェクト
- グローバルに登録されていないシンボル、例:
Symbol('my new symbol')
- イベントハンドラのイベント
サポートされるシリアライズ可能な戻り値は、バウンダリクライアントコンポーネントのシリアライズ可能なprops と同じです。
使用方法
フォーム内のサーバー関数
サーバー関数の最も一般的なユースケースは、データを変更する関数の呼び出しです。ブラウザでは、HTML form 要素 は、ユーザーが変更を送信するための従来の方法です。React Server Componentsでは、Reactはフォーム内のアクションとしてサーバー関数のファーストクラスサポートを導入しています。
ユーザーがユーザー名を要求できるフォームを以下に示します。
// 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
は、失敗したかどうかを知らせる必要があります。
段階的な機能強化をサポートしながら、サーバー関数の結果に基づいてUIを更新するには、useActionState
を使用します。
// requestUsername.js
'use server';
export default async function requestUsername(formData) {
const username = formData.get('username');
if (canRequest(username)) {
// ...
return 'successful';
}
return 'failed';
}
// UsernameForm.js
'use client';
import { useActionState } from 'react';
import requestUsername from './requestUsername';
function UsernameForm() {
const [state, action] = useActionState(requestUsername, null, 'n/a');
return (
<>
<form action={action}>
<input type="text" name="username" />
<button type="submit">Request</button>
</form>
<p>Last submission request returned: {state}</p>
</>
);
}
ほとんどのフックと同様に、useActionState
はクライアントコード内でのみ呼び出すことができます。
<form>
の外でのサーバー関数の呼び出し
サーバー関数はサーバー側のエンドポイントとして公開されており、クライアントコードの任意の場所で呼び出すことができます。
フォーム外のサーバー関数を使用する場合は、フォームコンポーネントの外でサーバー関数を呼び出す際は、ローディングインジケーターの表示、楽観的状態更新の実装、予期せぬエラーの処理を可能にするTransitionコンテキスト内で呼び出してください。フォーム内では、サーバー関数は自動的にTransitionでラップされます。
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>;
</>
);
}
// actions.js
'use server';
let likeCount = 0;
export default async function incrementLike() {
likeCount++;
return likeCount;
}
サーバー関数の戻り値を読み取るには、返されるPromiseをawait
する必要があります。