<Form> 组件扩展了 HTML <form> 元素,以提供
它对于更新 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>
)
}import Form from 'next/form'
export default function Search() {
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>
)
}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>
)
}import Form from 'next/form'
export default function Search() {
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:
action (字符串) 属性当 action 是一个字符串时,<Form> 组件支持以下属性:
| Prop | Example | Type | Required |
|---|---|---|---|
action | action="/search" | string (URL or relative path) | Yes |
replace | replace={false} | boolean | - |
scroll | scroll={true} | boolean | - |
action: 表单提交时导航到的 URL 或路径。
"" 将导航到具有更新搜索参数的相同路由。replace: 替换当前历史状态,而不是将新状态推入 浏览器历史记录 堆栈。默认为 false。scroll: 控制导航期间的滚动行为。默认为 true,这意味着它将滚动到新路由的顶部,并为向前和向后导航保持滚动位置。当 action 是一个字符串时,<Form> 组件支持以下属性:
| Prop | Example | Type | Required |
|---|---|---|---|
action | action="/search" | string (URL or relative path) | Yes |
replace | replace={false} | boolean | - |
scroll | scroll={true} | boolean | - |
prefetch | prefetch={true} | boolean | - |
action: 表单提交时导航到的 URL 或路径。
"" 将导航到具有更新搜索参数的相同路由。replace: 替换当前历史状态,而不是将新状态推入 浏览器历史记录 堆栈。默认为 false。scroll: 控制导航期间的滚动行为。默认为 true,这意味着它将滚动到新路由的顶部,并为向前和向后导航保持滚动位置。prefetch: 控制当表单在用户视口中变为可见时,是否应预加载路径。默认为 true。action (函数) 属性当 action 是一个函数时,<Form> 组件支持以下属性:
| Prop | Example | Type | Required |
|---|---|---|---|
action | action={myAction} | function (Server Action) | Yes |
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() 将会覆盖 <Form> 的行为,例如导航到指定的 URL。method, encType, target: 不受支持,因为它们会覆盖 <Form> 的行为。
formMethod、formEncType 和 formTarget 可用于分别覆盖 method、encType 和 target 属性,使用它们将回退到原生浏览器行为。<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>
)
}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> 在用户视口中变为可见时,/search 页面上的共享 UI(例如 layout.js 和 loading.js)将被预加载。提交后,表单将立即导航到新路由并显示加载 UI,同时正在获取结果。您可以使用 loading.js 设计回退 UI:
export default function Loading() {
return <div>Loading...</div>
}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>
)
}'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>
)
}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>
)
}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 函数导航到新的帖子页面。
须知:由于表单提交的“目的地”在 action 执行之前是未知的,因此
<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}`)
}'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 属性获取数据:
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 文档。