跳到主要內容

表單

<Form> 組件擴展了 HTML <form> 元素,以提供 預先載入 載入 UI 的功能, 提交時的 客戶端導航,以及 漸進式增強

對於更新 URL 搜尋參數的表單來說非常有用,因為它可以減少實現上述功能所需的樣板程式碼。

基本用法

/app/ui/search.tsx
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> 的行為就像原生 HTML 表單一樣,使用 GET 方法。表單資料會編碼到 URL 中作為搜尋參數,並且在提交表單時,它會導航到指定的 URL。此外,Next.js
    • 預先載入 表單可見時的路徑,這會預先載入共用 UI(例如 layout.jsloading.js),從而實現更快的導航。
    • 當提交表單時,執行 客戶端導航 而不是完整頁面重新載入。這保留了共用 UI 和客戶端狀態。
  • action函式 (伺服器行為) 時,<Form> 的行為就像 React 表單 一樣,在提交表單時執行該行為。

action (字串) Props

action 是字串時,<Form> 組件支援以下 props

屬性範例類型必填
actionaction="/search"string (URL 或相對路徑)
replacereplace={false}boolean-
scrollscroll={true}boolean-
prefetchprefetch={true}boolean-
  • action:表單提交時要導航到的 URL 或路徑。
    • 空字串 "" 將導航到具有更新搜尋參數的相同路由。
  • replace:替換目前的歷史記錄狀態,而不是將新的狀態推送到 瀏覽器的歷史記錄 堆疊。預設值為 false
  • scroll:控制導航期間的滾動行為。預設值為 true,這表示它將滾動到新路由的頂部,並保持後退和前進導航的滾動位置。
  • prefetch:控制當表單在使用者視窗中可見時,是否應預先載入路徑。預設值為 true

action (函式) Props

action 是函式時,<Form> 組件支援以下 prop

屬性範例類型必填
actionaction={myAction}function (伺服器行為)
  • action:表單提交時要呼叫的伺服器行為。請參閱 React 文件 以了解更多資訊。

小知識:當 action 是函式時,replacescroll props 會被忽略。

注意事項

  • formAction:可用於 <button><input type="submit"> 欄位中,以覆寫 action prop。Next.js 將執行客戶端導航,但是,此方法不支援預先載入。
    • 當使用 basePath 時,您還必須將其包含在 formAction 路徑中。例如:formAction="/base-path/search"
  • key:不支援將 key prop 傳遞給字串 action。如果您想觸發重新渲染或執行變更,請考慮改用函式 action
  • onSubmit:可用於處理表單提交邏輯。但是,呼叫 event.preventDefault() 將覆寫 <Form> 行為,例如導航到指定的 URL。
  • methodencTypetarget:由於它們會覆寫 <Form> 行為,因此不支援。
    • 同樣地,formMethodformEncTypeformTarget 可用於分別覆寫 methodencTypetarget props,使用它們將會回退到原生瀏覽器行為。
    • 如果您需要使用這些 props,請改用 HTML <form> 元素。
  • <input type="file">:當 action 是字串時,使用此輸入類型將會符合瀏覽器行為,提交檔案名稱而不是檔案物件。

範例

導向搜尋結果頁面的搜尋表單

您可以通過將路徑作為 action 傳遞來建立導航到搜尋結果頁面的搜尋表單

/app/page.tsx
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 prop 存取查詢,並使用它從外部來源取得資料。

/app/search/page.tsx
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.jsloading.js)將會被預先載入。提交時,表單將立即導航到新路由,並在取得結果時顯示載入 UI。您可以使用 loading.js 設計後備 UI

/app/search/loading.tsx
export default function Loading() {
  return <div>Loading...</div>
}

為了涵蓋共用 UI 尚未載入的情況,您可以使用 useFormStatus 向使用者顯示即時回饋。

首先,建立一個組件,在表單待處理時顯示載入狀態

/app/ui/search-button.tsx
'use client'
import { useFormStatus } from 'react-dom'
 
export default function SearchButton() {
  const status = useFormStatus()
  return (
    <button type="submit">{status.pending ? 'Searching...' : 'Search'}</button>
  )
}

然後,更新搜尋表單頁面以使用 SearchButton 組件

/app/page.tsx
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 prop 來執行變更。

/app/posts/create/page.tsx
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。

/app/posts/actions.ts
'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 prop 取得資料

/app/posts/[id]/page.tsx
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>
  )
}

請參閱 伺服器行為 文件以取得更多範例。