Next.js · LEARN AT YOUR OWN PACE今日も、一歩ずつ。

LESSON 12 · 約35分

フォームとServer Actions

入力を受け取り、安全にサーバーへ渡す流れを学びます。

コードを試す前に

基本演習はApp Router・JavaScript/JSX・Cache Components無効で進めます。11の有効化例は独立した発展実験です。01〜04は先に読んで、コードの実行は05の環境構築後に戻って試せます。

短い学習用の例です。各例は段階ごとの独立した例であり、全コードを一つのプロジェクトへ順に上書きして完成する形式ではありません。必要なファイル・依存関係・前提条件は注記に記載しています。

開発環境の準備を確認する →

このレッスンでわかること

  • form actionとServer Functionをつなげられる
  • 入力検証・送信中・結果の表示を組み立てられる

読み取りと更新を分ける

読み取りはデータを表示するための処理。更新はユーザーの意図を受けてデータを書き換える処理です。描画の途中で勝手に保存せず、フォームや操作を入口にします。Server Functionはサーバーで動く非同期関数で、更新に使う文脈ではServer Actionと呼びます。

form actionがFormDataを渡す

use serverで宣言した関数をformのactionに渡せます。useActionStateと組み合わせる場合、関数の第1引数は前の状態、第2引数がFormDataです。想定内の入力エラーは戻り値で返し、画面に具体的な直し方を示します。

サーバーで毎回確認する

ブラウザー側のrequiredだけでは不十分です。型・長さ・許可する値に加え、保存や削除の前には認証と対象への権限を確認します。Server ActionsはUIを経由せず呼ばれる可能性がある公開エンドポイントとして扱います。

検証だけを行う学習用Action

app/actions.js
'use server'

export async function checkTitle(previousState, formData) {
  const title = formData.get('title')
  if (typeof title !== 'string' || title.trim().length < 2) {
    return { message: 'タイトルを2文字以上で入力してください。' }
  }
  return { message: `「${title.trim()}」を確認しました。` }
}

入力検証だけのデモです。DBへの保存やアカウント操作は実装していません。

送信中と結果を表示

app/ui/note-form.jsx
'use client'

import { useActionState } from 'react'
import { checkTitle } from '../actions'

export default function NoteForm() {
  const [state, formAction, pending] = useActionState(checkTitle, { message: '' })
  return (
    <form action={formAction}>
      <label htmlFor="title">ノートのタイトル</label>
      <input id="title" name="title" required />
      <button disabled={pending}>{pending ? '確認中…' : '確認する'}</button>
      <p aria-live="polite">{state.message}</p>
    </form>
  )
}

page.jsxからNoteFormを読み込んで使います。保存処理を足す場合は認証・認可・更新後の再検証も追加します。

TRY IT YOURSELF

エラーメッセージを改善する

  1. 1文字で送信して結果を見る
  2. 上限80文字の検証を追加する
  3. 空白だけの入力で試す

できたらOK:送信中と入力エラーが分かり、再入力できる

QUICK CHECK

理解を確かめよう

Server Actionの安全性について適切なのは?

公式資料でもう少し詳しく

ここまで読めたら、ひとつ前進。