フォーム
<Form>
コンポーネントはHTMLの<form>
要素を拡張し、プリフェッチによるローディングUI、 送信時のクライアントサイドナビゲーション、そしてプログレッシブエンハンスメントを提供します。
これは、URLの検索パラメータを更新するフォームに役立ちます。上記の機能を実現するために必要な定型コードを減らすことができるためです。
基本的な使用法
import Form from 'next/form'
export default function Page() {
return (
<Form action="/search">
{/* On submission, the input value will be appended to
the URL, e.g. /search?query=abc */}
<input name="query" />
<button type="submit">Submit</button>
</Form>
)
}
リファレンス
<Form>
コンポーネントの動作は、action
プロップにstring
またはfunction
のどちらが渡されるかによって異なります。
action
が文字列の場合、<Form>
はGET
メソッドを使用するネイティブHTMLフォームのように動作します。フォームデータはURLに検索パラメータとしてエンコードされ、フォームが送信されると、指定されたURLへナビゲートします。さらに、Next.jsは- フォームが表示されるとパスをプリフェッチし、共有UI (例:
layout.js
やloading.js
) をプリロードすることで、ナビゲーションを高速化します。 - フォームが送信されると、ページ全体の再ロードではなく、クライアントサイドナビゲーションを実行します。これにより、共有UIとクライアントサイドの状態が維持されます。
- フォームが表示されるとパスをプリフェッチし、共有UI (例:
action
が関数(サーバーアクション)の場合、<Form>
はReactフォームのように動作し、フォームが送信されるとアクションを実行します。
action
(文字列) Props
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
(関数) Props
action
が関数の場合、<Form>
コンポーネントは以下のプロップをサポートします
プロップ | 例 | 型 | 必須 |
---|---|---|---|
action | action={myAction} | function (サーバーアクション) | はい |
action
: フォームが送信されたときに呼び出されるサーバーアクション。詳細については、Reactのドキュメントを参照してください。
豆知識:
action
が関数の場合、replace
とscroll
プロップは無視されます。
注意点
formAction
:<button>
または<input type="submit">
フィールドでaction
プロップをオーバーライドするために使用できます。Next.jsはクライアントサイドナビゲーションを実行しますが、このアプローチはプリフェッチをサポートしていません。basePath
を使用する場合、formAction
パスにも含める必要があります。例:formAction="/base-path/search"
。
key
: 文字列のaction
にkey
プロップを渡すことはサポートされていません。再レンダリングをトリガーしたり、ミューテーションを実行したい場合は、代わりにfunction
の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">Submit</button>
</Form>
)
}
ユーザーがクエリ入力フィールドを更新してフォームを送信すると、フォームデータは検索パラメータとして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
など)がプリフェッチされます。送信時には、フォームはすぐに新しいルートにナビゲートし、結果がフェッチされている間、ローディングUIを表示します。loading.js
を使用してフォールバックUIを設計できます
export default function Loading() {
return <div>Loading...</div>
}
共有UIがまだロードされていないケースに対応するため、useFormStatus
を使用して、ユーザーに即座のフィードバックを表示できます。
まず、フォームが保留中のときにローディング状態を表示するコンポーネントを作成します
'use client'
import { useFormStatus } from 'react-dom'
export default function SearchButton() {
const status = useFormStatus()
return (
<button type="submit">{status.pending ? 'Searching...' : 'Search'}</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>
)
}
サーバーアクションによるミューテーション
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">Create Post</button>
</Form>
)
}
ミューテーション後、新しいリソースにリダイレクトすることは一般的です。next/navigation
のredirect
関数を使用して、新しい投稿ページにナビゲートできます。
豆知識: フォーム送信の「宛先」はアクションが実行されるまで不明であるため、
<Form>
は共有UIを自動的にプリフェッチできません。
'use server'
import { redirect } from 'next/navigation'
export async function createPost(formData: FormData) {
// Create a new post
// ...
// Redirect to the new post
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>
)
}
詳細な例については、サーバーアクションのドキュメントを参照してください。
お役に立ちましたか?