4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Next.js 15で追加されたFormコンポーネントで遷移前に処理を行う

Last updated at Posted at 2024-11-06

next/form

FormコンポーネントがNext.jsのバージョン15で追加されました。

Formformを拡張したコンポーネントで、画面遷移する検索フォームやサーバーアクションによるミューテーションで利用されます。

import Form from 'next/form'
import { createPost } from '@/posts/actions'

------------------------------------------------
// 検索フォーム
function Page() {
  return (
    <Form action="/search">
      <input name="query" />
      <button type="submit">Submit</button>
    </Form>
  )
}
------------------------------------------------
// サーバーアクション
function Page() {
  return (
    <Form action={createPost}>
      <input name="title" />
      <button type="submit">Create Post</button>
    </Form>
  )
}

actionには文字列と関数(サーバーアクション)を渡せます。

文字列が渡されたときは送信のタイミングでナビゲーションが行われます。遷移先はactionに渡した文字列をパスに、フォームデータを元にした検索パラメータを組み合わせたURLになります。上記の例では/search?query=xxxに遷移します(xxxはinputの入力)。

ナビゲーションはLinkコンポーネントと同じような振る舞いをします。JavaScriptが読み込まれていないときはハードナビゲーションが、読み込まれている場合はソフトナビゲーションが行われます。
さらに、フォームが表示されたタイミングで遷移先のレイアウト(layout.tsx)と読み込み状態(loading.tsx)を事前に取得します。

これらの機能を持つ`Form`コンポーネントを実装した例
Next15のBlogより引用
// Note: This is abbreviated for demonstration purposes.
// Not recommended for use in production code.
 
'use client'
 
import { useEffect } from 'react'
import { useRouter } from 'next/navigation'
 
export default function Form(props) {
  const action = props.action
  const router = useRouter()
 
  useEffect(() => {
    // if form target is a URL, prefetch it
    if (typeof action === 'string') {
      router.prefetch(action)
    }
  }, [action, router])
 
  function onSubmit(event) {
    event.preventDefault()
 
    // grab all of the form fields and trigger a `router.push` with the data URL encoded
    const formData = new FormData(event.currentTarget)
    const data = new URLSearchParams()
 
    for (const [name, value] of formData) {
      data.append(name, value as string)
    }
 
    router.push(`${action}?${data.toString()}`)
  }
 
  if (typeof action === 'string') {
    return <form onSubmit={onSubmit} {...props} />
  }
 
  return <form {...props} />
}

実際にnextから提供されているFormコンポーネントの実装はこちら

遷移前に処理を行う

Formを用いた遷移の前に、フォームデータのバリデーションのような何らかの処理を挟みたい場合は、FormonSubmitを渡します。

function Page() {
  const handleSubmit = (e) => {
    validateFormData(e.currentTarget);
  };

  return (
    <Form action="/search" onSubmit={handleSubmit}>
      <input name="query" />
      <button type="submit">Submit</button>
    </Form>
  )
}

上記の例では遷移の前にvalidateFormDataが実行されます。

これだけではvalidateFormDataの結果によらず、実行後に規定の遷移を誘発してしまいます。
onSubmitの処理によって、遷移を停止したい場合は、e.preventDefault()を呼び出します(参考)

function Page() {
  const handleSubmit = (e) => {
    const result = validateFormData(e.currentTarget);
    if (!result.success) {
      e.preventDefault();
    }
  };

  return (
    <Form action="/search" onSubmit={handleSubmit}>
      <input name="query" />
      <button type="submit">Submit</button>
    </Form>
  )
}

この例ではvalidateFormDataが失敗した場合はe.preventDefault()呼ばれるので、遷移が行われません。

特定の値を返したり、早期returnすることで遷移されない期待も抱いてしまうのは否めないので、e.preventDefault()を忘れないようにしましょう。

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?