表单
<Form>
组件扩展了 HTML <form>
元素,以提供 加载 UI 中的 prefetching、提交时的客户端导航和渐进式增强。
¥The <Form>
component extends the HTML <form>
element to provide prefetching of loading UI, client-side navigation on submission, and progressive enhancement.
它对于更新 URL 搜索参数的表单很有用,因为它减少了实现上述目标所需的样板代码。
¥It's useful for forms that update URL search params as it reduces the boilerplate code needed to achieve the above.
基本用法:
¥Basic usage:
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 Search() {
return (
<Form action="/search">
<input name="query" />
<button type="submit">Submit</button>
</Form>
)
}
参考
¥Reference
<Form>
组件的行为取决于 action
prop 传递的是 string
还是 function
。
¥The behavior of the <Form>
component depends on whether the action
prop is passed a string
or function
.
-
当
action
为字符串时,<Form>
的行为类似于使用GET
方法的原生 HTML 表单。表单数据作为搜索参数编码到 URL 中,提交表单时,会导航到指定的 URL。此外,Next.js:¥When
action
is a string, the<Form>
behaves like a native HTML form that uses aGET
method. The form data is encoded into the URL as search params, and when the form is submitted, it navigates to the specified URL. In addition, Next.js:-
预取 表单可见时的路径,这会预加载共享 UI(例如
layout.js
和loading.js
),从而加快导航速度。¥Prefetches the path when the form becomes visible, this preloads shared UI (e.g.
layout.js
andloading.js
), resulting in faster navigation. -
提交表单时执行 客户端导航 而不是整个页面重新加载。这保留了共享的 UI 和客户端状态。
¥Performs a client-side navigation instead of a full page reload when the form is submitted. This retains shared UI and client-side state.
-
-
当
action
是一个函数(服务器操作)时,<Form>
的行为类似于 React 表单,在提交表单时执行操作。¥When
action
is a function (Server Action),<Form>
behaves like a React form, executing the action when the form is submitted.
action
(字符串)属性
¥action
(string) Props
当 action
是字符串时,<Form>
组件支持以下 props:
¥When action
is a string, the <Form>
component supports the following props:
属性 | 示例 | 类型 | 必需的 |
---|---|---|---|
action | action="/search" | string (URL 或相对路径) | 是的 |
replace | replace={false} | boolean | * |
scroll | scroll={true} | boolean | * |
prefetch | prefetch={true} | boolean | * |
-
action
:提交表单时要导航到的 URL 或路径。¥**
action
**: The URL or path to navigate to when the form is submitted.-
空字符串
""
将导航到具有更新的搜索参数的相同路由。¥An empty string
""
will navigate to the same route with updated search params.
-
-
replace
:替换当前历史状态,而不是将新状态推送到 浏览器的历史 堆栈。默认为false
。¥**
replace
**: Replaces the current history state instead of pushing a new one to the browser's history stack. Default isfalse
. -
scroll
:控制导航期间的滚动行为。默认为true
,这意味着它将滚动到新路由的顶部,并保持滚动位置以进行前后导航。¥**
scroll
**: Controls the scroll behavior during navigation. Defaults totrue
, this means it will scroll to the top of the new route, and maintain the scroll position for backwards and forwards navigation. -
prefetch
:控制当表单在用户视口中可见时是否应预取路径。默认为true
。¥**
prefetch
**: Controls whether the path should be prefetched when the form becomes visible in the user's viewport. Defaults totrue
.
action
(函数)属性
¥action
(function) Props
当 action
为函数时,<Form>
组件支持以下 prop:
¥When action
is a function, the <Form>
component supports the following prop:
属性 | 示例 | 类型 | 必需的 |
---|---|---|---|
action | action={myAction} | function (服务器操作) | 是的 |
-
action
:提交表单时要调用的服务器操作。有关更多信息,请参阅 React 文档。¥**
action
**: The Server Action to be called when the form is submitted. See the React docs for more.
很高兴知道:当
action
是一个函数时,replace
和scroll
属性将被忽略。¥Good to know: When
action
is a function, thereplace
andscroll
props are ignored.
注意事项
¥Caveats
-
formAction
:可以在<button>
或<input type="submit">
字段中使用以覆盖action
属性。Next.js 将执行客户端导航,但是,这种方法不支持预取。¥**
formAction
**: Can be used in a<button>
or<input type="submit">
fields to override theaction
prop. Next.js will perform a client-side navigation, however, this approach doesn't support prefetching. -
key
:不支持将key
prop 传递给字符串action
。如果你想触发重新渲染或执行修改,请考虑改用函数action
。¥**
key
**: Passing akey
prop to a stringaction
is not supported. If you'd like to trigger a re-render or perform a mutation, consider using a functionaction
instead. -
onSubmit
:可用于处理表单提交逻辑。但是,调用event.preventDefault()
将覆盖<Form>
行为,例如导航到指定的 URL。¥**
onSubmit
**: Can be used to handle form submission logic. However, callingevent.preventDefault()
will override<Form>
behavior such as navigating to the specified URL. -
method
,encType
,target
:不受支持,因为它们会覆盖<Form>
行为。¥**
method
,encType
,target
**: Are not supported as they override<Form>
behavior.-
类似地,
formMethod
、formEncType
和formTarget
可分别用于覆盖method
、encType
和target
属性,使用它们将恢复到原生浏览器行为。¥Similarly,
formMethod
,formEncType
, andformTarget
can be used to override themethod
,encType
, andtarget
props respectively, and using them will fallback to native browser behavior. -
如果你需要使用这些属性,请改用 HTML
<form>
元素。¥If you need to use these props, use the HTML
<form>
element instead.
-
-
<input type="file">
:当action
是字符串时,使用此输入类型将通过提交文件名而不是文件对象来匹配浏览器行为。¥**
<input type="file">
**: Using this input type when theaction
is a string will match browser behavior by submitting the filename instead of the file object.
示例
¥Examples
指向搜索结果页面的搜索表单
¥Search form that leads to a search result page
你可以通过将路径作为 action
传递来创建导航到搜索结果页面的搜索表单:
¥You can create a search form that navigates to a search results page by passing the path as an 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
。
¥When the user updates the query input field and submits the form, the form data will be encoded into the URL as search params, e.g. /search?query=abc
.
很高兴知道:如果你将空字符串
""
传递给action
,则表单将导航到具有更新搜索参数的相同路由。¥Good to know: If you pass an empty string
""
toaction
, the form will navigate to the same route with updated search params.
在结果页面上,你可以使用 searchParams
page.js
prop 访问查询,并使用它来从外部源获取数据。
¥On the results page, you can access the query using the searchParams
page.js
prop and use it to fetch data from an external source.
import { getSearchResults } from '@/lib/search'
export default async function SearchPage({
searchParams,
}: {
searchParams: { [key: string]: string | string[] | undefined }
}) {
const results = await getSearchResults(searchParams.query)
return <div>...</div>
}
import { getSearchResults } from '@/lib/search'
export default async function SearchPage({ searchParams }) {
const results = await getSearchResults(searchParams.query)
return <div>...</div>
}
当 <Form>
在用户的视口中可见时,/search
页面上的共享 UI(例如 layout.js
和 loading.js
)将被预取。提交后,表单将立即导航到新路由并在获取结果时显示加载 UI。你可以使用 loading.js
设计回退 UI:
¥When the <Form>
becomes visible in the user's viewport, shared UI (such as layout.js
and loading.js
) on the /search
page will be prefetched. On submission, the form will immediately navigate to the new route and show loading UI while the results are being fetched. You can design the fallback UI using loading.js
:
export default function Loading() {
return <div>Loading...</div>
}
export default function Loading() {
return <div>Loading...</div>
}
要涵盖共享 UI 尚未加载的情况,你可以使用 useFormStatus
向用户显示即时反馈。
¥To cover cases when shared UI hasn't yet loaded, you can show instant feedback to the user using useFormStatus
.
首先,创建一个在表单待处理时显示加载状态的组件:
¥First, create a component that displays a loading state when the form is pending:
'use client'
import { useFormStatus } from 'react-dom'
export default function SearchButton() {
const status = useFormStatus()
return (
<button type="submit">{status.pending ? 'Searching...' : 'Search'}</button>
)
}
'use client'
import { useFormStatus } from 'react-dom'
export default function SearchButton() {
const status = useFormStatus()
return (
<button type="submit">{status.pending ? 'Searching...' : 'Search'}</button>
)
}
然后,更新搜索表单页面以使用 SearchButton
组件:
¥Then, update the search form page to use the SearchButton
component:
import Form from 'next/form'
import { SearchButton } from '@/ui/search-button'
export default function Page() {
return (
<Form action="/search">
<input name="query" />
<SearchButton />
</Form>
)
}
import Form from 'next/form'
import { SearchButton } from '@/ui/search-button'
export default function Page() {
return (
<Form action="/search">
<input name="query" />
<SearchButton />
</Form>
)
}
使用服务器操作进行修改
¥Mutations with Server Actions
你可以通过将函数传递给 action
属性来执行修改。
¥You can perform mutations by passing a function to the action
prop.
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>
)
}
突变后,重定向到新资源是很常见的。你可以使用 next/navigation
中的 redirect
函数导航到新帖子页面。
¥After a mutation, it's common to redirect to the new resource. You can use the redirect
function from next/navigation
to navigate to the new post page.
很高兴知道:由于表单提交的 "destination" 在执行操作之前是未知的,因此
<Form>
无法自动预取共享 UI。¥Good to know: Since the "destination" of the form submission is not known until the action is executed,
<Form>
cannot automatically prefetch shared 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}`)
}
'use server'
import { redirect } from 'next/navigation'
export async function createPost(formData) {
// Create a new post
// ...
// Redirect to the new post
redirect(`/posts/${data.id}`)
}
然后,在新页面中,你可以使用 params
prop 获取数据:
¥Then, in the new page, you can fetch data using the params
prop:
import { getPost } from '@/posts/data'
export default async function PostPage({
params,
}: {
params: Promise<{ id: string }>
}) {
const data = await getPost((await params).id)
return (
<div>
<h1>{data.title}</h1>
</div>
)
}
import { getPost } from '@/posts/data'
export default async function PostPage({ params }) {
const data = await getPost((await params).id)
return (
<div>
<h1>{data.title}</h1>
</div>
)
}
有关更多示例,请参阅 服务器操作 文档。
¥See the Server Actions docs for more examples.