Form コンポーネント
<Form> コンポーネントは HTML の <form> 要素を拡張し、プリフェッチとloading UI、クライアント側ナビゲーション、およびプログレッシブエンハンスメントを提供します。
URL 検索パラメータを更新するフォームに役立ちます。上記を実現するために必要なボイラープレートコードを削減できます。
基本的な使用方法:
import Form from 'next/form'
export default function Page() {
return (
<Form action="/search">
{/* 送信時、入力値が URL に追加されます。
例:/search?query=abc */}
<input name="query" />
<button type="submit">送信</button>
</Form>
)
}リファレンス
<Form> コンポーネントの動作は、action プロップに string または function が渡されるかによって異なります。
actionが文字列の場合、<Form>はGETメソッドを使用するネイティブ HTML フォームのように動作します。フォームデータは URL に検索パラメータとしてエンコードされ、フォーム送信時に指定された URL にナビゲートします。さらに、Next.js は以下を行います:- プリフェッチを実行します。フォームがビューポートに表示されたとき、共有 UI(例:
layout.jsやloading.js)を事前読み込みし、より高速なナビゲーションを実現します。 - フォーム送信時に完全なページ再読み込みの代わりにクライアント側ナビゲーションを実行します。これにより、共有 UI とクライアント側の状態を保持します。
- プリフェッチを実行します。フォームがビューポートに表示されたとき、共有 UI(例:
actionが関数(Server Action)の場合、<Form>はReact フォームのように動作し、フォーム送信時にアクションを実行します。
action(文字列)プロップ
action が文字列の場合、<Form> コンポーネントは以下のプロップをサポートします:
| プロップ | 例 | 型 | 必須 |
|---|---|---|---|
action | action="/search" | string(URL または相対パス) | はい |
replace | replace={false} | boolean | - |
scroll | scroll={true} | boolean | - |
prefetch | prefetch={true} | boolean | - |
action:フォーム送信時にナビゲートする URL またはパス。- 空の文字列
""は、同じルートに検索パラメータを更新してナビゲートします。
- 空の文字列
replace:ブラウザの履歴スタックに新しい状態をプッシュする代わりに、現在の履歴状態を置き換えます。デフォルトはfalseです。scroll:ナビゲーション中のスクロール動作を制御します。デフォルトはtrueです。新しいルートの上部までスクロールし、戻る・進むナビゲーション時のスクロール位置を保持します。prefetch:ユーザーのビューポートにフォームが表示されたときにパスをプリフェッチすべきかを制御します。デフォルトはtrueです。
action(関数)プロップ
action が関数の場合、<Form> コンポーネントは以下のプロップをサポートします:
| プロップ | 例 | 型 | 必須 |
|---|---|---|---|
action | action={myAction} | function(Server Action) | はい |
action:フォーム送信時に呼び出される Server Action。詳細は React ドキュメントを参照してください。
補足:
actionが関数の場合、replaceとscrollプロップは無視されます。
注意事項
formAction:<button>または<input type="submit">フィールドでactionプロップをオーバーライドする場合に使用できます。Next.js はクライアント側ナビゲーションを実行しますが、このアプローチはプリフェッチをサポートしません。basePathを使用する場合は、formActionパスにも含める必要があります。例:formAction="/base-path/search"。
key:文字列actionにkeyプロップを渡すことはサポートされていません。再レンダリングをトリガーしたいか、ミューテーションを実行したい場合は、関数actionを使用することを検討してください。
onSubmit:フォーム送信ロジックを処理するために使用できます。ただし、event.preventDefault()を呼び出すと、指定された URL へのナビゲーションなど<Form>の動作がオーバーライドされます。method、encType、target:<Form>の動作をオーバーライドするためサポートされていません。- 同様に、
formMethod、formEncType、formTargetを使用して、method、encType、targetプロップをそれぞれオーバーライドできます。これらを使用するとネイティブブラウザ動作にフォールバックします。 - これらのプロップを使用する必要がある場合は、HTML
<form>要素を代わりに使用してください。
- 同様に、
<input type="file">:actionが文字列の場合にこの入力タイプを使用すると、ブラウザ動作と一致して、ファイルオブジェクトの代わりにファイル名を送信します。
例
検索結果ページにリードする検索フォーム
action にパスを渡して、検索結果ページにナビゲートする検索フォームを作成できます:
import Form from 'next/form'
export default function Page() {
return (
<Form action="/search">
<input name="query" />
<button type="submit">送信</button>
</Form>
)
}開発者が query 入力フィールドを更新してフォームを送信すると、フォームデータは検索パラメータとして URL にエンコードされます。例:/search?query=abc。
補足:
actionに空の文字列""を渡すと、フォームは同じルートに検索パラメータを更新してナビゲートします。
結果ページでは、searchParams page.js プロップを使用してクエリにアクセスし、外部ソースからデータを取得するために使用できます。
import { getSearchResults } from '@/lib/search'
export default async function SearchPage({
searchParams,
}: {
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
}) {
const results = await getSearchResults((await searchParams).query)
return <div>...</div>
}<Form> がユーザーのビューポートに表示されると、/search ページの共有 UI(layout.js や loading.js など)がプリフェッチされます。送信時、フォームは新しいルートにすぐにナビゲートし、結果を取得中に loading UI を表示します。loading.js を使用してフォールバック UI を設計できます:
export default function Loading() {
return <div>読込中...</div>
}共有 UI がまだ読み込まれていない場合に対応するために、useFormStatus を使用してユーザーに即座にフィードバックを表示できます。
まず、フォームが保留中のときに読込状態を表示するコンポーネントを作成します:
'use client'
import { useFormStatus } from 'react-dom'
export default function SearchButton() {
const status = useFormStatus()
return (
<button type="submit">{status.pending ? '検索中...' : '検索'}</button>
)
}次に、SearchButton コンポーネントを使用するように検索フォームページを更新します:
import Form from 'next/form'
import { SearchButton } from '@/ui/search-button'
export default function Page() {
return (
<Form action="/search">
<input name="query" />
<SearchButton />
</Form>
)
}Server Actions によるミューテーション
action プロップに関数を渡してミューテーションを実行できます。
import Form from 'next/form'
import { createPost } from '@/posts/actions'
export default function Page() {
return (
<Form action={createPost}>
<input name="title" />
{/* ... */}
<button type="submit">投稿を作成</button>
</Form>
)
}ミューテーション後、新しいリソースにリダイレクトするのが一般的です。next/navigation から redirect 関数を使用して新しい投稿ページにナビゲートできます。
補足:フォーム送信の「送信先」はアクション実行まで不明なため、
<Form>は共有 UI を自動的にプリフェッチできません。
'use server'
import { redirect } from 'next/navigation'
export async function createPost(formData: FormData) {
// 新しい投稿を作成
// ...
// 新しい投稿にリダイレクト
redirect(`/posts/${data.id}`)
}その後、新しいページで params プロップを使用してデータを取得できます:
import { getPost } from '@/posts/data'
export default async function PostPage({
params,
}: {
params: Promise<{ id: string }>
}) {
const { id } = await params
const data = await getPost(id)
return (
<div>
<h1>{data.title}</h1>
{/* ... */}
</div>
)
}詳細は Server Actions ドキュメントを参照してください。