Форма (Form)
Компонент <Form>
расширяет HTML-элемент <form>
, предоставляя префетчинг для UI загрузки, клиентскую навигацию при отправке и прогрессивное улучшение.
Он особенно полезен для форм, обновляющих параметры поиска в URL, так как сокращает количество шаблонного кода.
Базовое использование:
import Form from 'next/form'
export default function Page() {
return (
<Form action="/search">
{/* При отправке значение input будет добавлено к
URL, например /search?query=abc */}
<input name="query" />
<button type="submit">Submit</button>
</Form>
)
}
import Form from 'next/form'
export default function Search() {
return (
<Form action="/search">
{/* При отправке значение input будет добавлено к
URL, например /search?query=abc */}
<input name="query" />
<button type="submit">Submit</button>
</Form>
)
}
Справочник
Поведение компонента <Form>
зависит от того, передается ли в проп action
строка (string
) или функция (function
).
- Когда
action
— это строка,<Form>
ведет себя как нативная HTML-форма с методомGET
. Данные формы кодируются в URL как параметры поиска, и при отправке формы происходит переход по указанному URL. Дополнительно Next.js:- Префетчит путь, когда форма становится видимой, предзагружая общий UI (например,
layout.js
иloading.js
), что ускоряет навигацию. - Выполняет клиентскую навигацию вместо полной перезагрузки страницы, сохраняя общий UI и клиентское состояние.
- Префетчит путь, когда форма становится видимой, предзагружая общий UI (например,
- Когда
action
— это функция (Server Action),<Form>
ведет себя как React-форма, выполняя действие при отправке формы.
Пропсы action
(string)
Когда 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
(function)
Когда 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
: Передача пропсаkey
для строковогоaction
не поддерживается. Если нужно вызвать ререндер или мутацию, используйте функциюaction
.
onSubmit
: Может использоваться для обработки логики отправки формы. Однако вызовevent.preventDefault()
переопределит поведение<Form>
, например переход по указанному URL.method
,encType
,target
: Не поддерживаются, так как переопределяют поведение<Form>
.- Аналогично,
formMethod
,formEncType
иformTarget
могут использоваться для переопределения соответствующих пропсов, но их использование приведет к нативному поведению браузера. - Если эти пропсы необходимы, используйте HTML-элемент
<form>
.
- Аналогично,
<input type="file">
: Использование этого типа input при строковомaction
приведет к поведению браузера по умолчанию — отправке имени файла вместо объекта файла.
Примеры
Форма поиска с переходом на страницу результатов
Можно создать форму поиска, которая переходит на страницу результатов, передав путь в action
:
import Form from 'next/form'
export default function Page() {
return (
<Form action="/search">
<input name="query" />
<button type="submit">Submit</button>
</Form>
)
}
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>
}
import { getSearchResults } from '@/lib/search'
export default async function SearchPage({ searchParams }) {
const results = await getSearchResults((await searchParams).query)
return <div>...</div>
}
Когда <Form>
становится видимой в области просмотра, общий UI (например, layout.js
и loading.js
) на странице /search
будет префетчен. При отправке форма немедленно перейдет на новый маршрут и покажет UI загрузки во время получения результатов. Fallback UI можно настроить с помощью loading.js
:
export default function Loading() {
return <div>Loading...</div>
}
export default function Loading() {
return <div>Loading...</div>
}
Для случаев, когда общий UI еще не загружен, можно показать мгновенную обратную связь с помощью useFormStatus
.
Сначала создайте компонент, отображающий состояние загрузки при ожидании формы:
Затем обновите страницу формы поиска, чтобы использовать компонент 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">Create Post</button>
</Form>
)
}
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>
)
}
После мутации обычно выполняется перенаправление на новый ресурс. Можно использовать функцию redirect
из next/navigation
для перехода на страницу нового поста.
Важно: Поскольку "назначение" отправки формы неизвестно до выполнения действия,
<Form>
не может автоматически префетчить общий UI.
'use server'
import { redirect } from 'next/navigation'
export async function createPost(formData: FormData) {
// Создание нового поста
// ...
// Перенаправление на новый пост
redirect(`/posts/${data.id}`)
}
'use server'
import { redirect } from 'next/navigation'
export async function createPost(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>
)
}
import { getPost } from '@/posts/data'
export default async function PostPage({ params }) {
const { id } = await params
const data = await getPost(id)
return (
<div>
<h1>{data.title}</h1>
{/* ... */}
</div>
)
}
Дополнительные примеры см. в документации по Server Actions.