Skip to main content

表单

<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 a GET 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.jsloading.js),从而加快导航速度。

      ¥Prefetches the path when the form becomes visible, this preloads shared UI (e.g. layout.js and loading.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:

属性示例类型必需的
actionaction="/search"string(URL 或相对路径)是的
replacereplace={false}boolean*
scrollscroll={true}boolean*
prefetchprefetch={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 is false.

  • scroll:控制导航期间的滚动行为。默认为 true,这意味着它将滚动到新路由的顶部,并保持滚动位置以进行前后导航。

    ¥**scroll**: Controls the scroll behavior during navigation. Defaults to true, 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 to true.

action(函数)属性

¥action (function) Props

action 为函数时,<Form> 组件支持以下 prop:

¥When action is a function, the <Form> component supports the following prop:

属性示例类型必需的
actionaction={myAction}function(服务器操作)是的
  • action:提交表单时要调用的服务器操作。有关更多信息,请参阅 React 文档

    ¥**action**: The Server Action to be called when the form is submitted. See the React docs for more.

很高兴知道:当 action 是一个函数时,replacescroll 属性将被忽略。

¥Good to know: When action is a function, the replace and scroll 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 the action prop. Next.js will perform a client-side navigation, however, this approach doesn't support prefetching.

    • 使用 basePath 时,你还必须将其包含在 formAction 路径中。例如 formAction="/base-path/search"

      ¥When using basePath, you must also include it in the formAction path. e.g. formAction="/base-path/search".

  • key:不支持将 key prop 传递给字符串 action。如果你想触发重新渲染或执行修改,请考虑改用函数 action

    ¥**key**: Passing a key prop to a string action is not supported. If you'd like to trigger a re-render or perform a mutation, consider using a function action instead.

  • onSubmit:可用于处理表单提交逻辑。但是,调用 event.preventDefault() 将覆盖 <Form> 行为,例如导航到指定的 URL。

    ¥**onSubmit**: Can be used to handle form submission logic. However, calling event.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.

    • 类似地,formMethodformEncTypeformTarget 可分别用于覆盖 methodencTypetarget 属性,使用它们将恢复到原生浏览器行为。

      ¥Similarly, formMethod, formEncType, and formTarget can be used to override the method, encType, and target 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 the action 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 "" to action, 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.jsloading.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.