本文へ移動
verified onnext@16.3.5react@19
最終検証日 2026-09-26
Next.js道場

Next.js のフォーム送信。入出力の最小構成サンプル

入力を受け取って結果を返すだけなら、ファイルは4つで足ります。

動いているものを触る/demo/io

ファイル構成

並んでいるのは、上の画面をいま動かしている本物のファイルです。名前を押すと中身が出ます。

ファイル構成
  • app/
  • done/
app/layout.tsxBuild

全ページの外側。本物のプロジェクトでは html と body をここで書きます

import type { Metadata } from "next";
 
export const metadata: Metadata = {
  title: "入出力の最小構成",
};
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return <main>{children}</main>;
}
.tsx
画面を返すファイル。HTML のような書き方ができます
.ts
画面を返さないファイル。処理とデータだけを置きます。ここに画面を書くと原因を名指ししないエラーで落ちます
Build
ビルド時に一度だけ動きます
Server
アクセスのたびにサーバーで動きます
Browser
利用者の手元で動きます

4つで足りる

「入力を受け取って、結果を返す」だけなら、必要なのはページが2つと、受け取る関数が1つと、外側が1つです。

送信ボタンを押してから、結果が出るまで
  1. Browser
    フォームを送る

    普通の form の送信。JavaScript が読み込まれる前でも押せる。

  2. Server
    actions.ts が受け取る

    値を切り詰めて、結果のページへ送り出す。この関数の中身はブラウザに届かない。

  3. Server
    done/page.tsx が描く

    受け取った値を出す。エスケープは React がやる。

'use client' はどこにも書いていません。状態もイベントも使っていないからです。

入力はどこで受け止めるか

app/actions.ts の先頭に 'use server' があります。これは「この関数をクライアントから呼べるようにする」という指示で、境界に穴を1つ開ける操作です。

穴である以上、画面を経由せずに誰でも呼べます。だから受け取った値は、その関数の中で必ず絞ります。

const text = String(formData.get('text') ?? '')
  .trim()
  .slice(0, 40)

入力欄に maxLength を書いてありますが、それは目安であって守りではありません。ブラウザ側の指定は簡単に外せます。長さを決めているのはサーバー側のこの行です。

なぜ結果を別のページにしたか

同じページで結果まで出そうとすると、状態が要ります。状態が要るとフックが要り、フックが要ると 'use client' が要ります。

送り先を別のページにすれば、その連鎖が起きません。送信のあとに redirect で移るこの形は、ブラウザの戻る操作とも噛み合います。

同じページに出したい場合は、Server Function の呼び方にある useActionState を使います。そのときは、そのファイルだけが Client Component になります。

ここから足していくとき

  • 保存するなら、actions.ts の中でデータベースへ書きます。ページ側は変わりません
  • 入力の形を厳しく見るなら、同じ場所で検証ライブラリを通します
  • 結果を同じ画面に出したくなったら、その部分だけを Client Component へ切り出します

足す場所はいつも同じで、actions.ts の中か、切り出した葉の部分です。ページを丸ごと Client Component にする必要は最後まで出てきません。

入れていないもの

このまま本番に持っていかないでください。省いてあるのは次の点です。

  • データベース。受け取った値はどこにも保存していません
  • 入力の細かい検証。長さを切るだけで、形式は見ていません
  • 失敗したときの画面。ここでは元のページへ戻すだけです
  • 設定ファイル。package.json と next.config.ts は作られたままです

出典

このページの内容は上記の一次情報を基準に書いています。個人ブログや二次情報を根拠にしていません。

理解できたか試す

では、このコードはどうなりますか。

このページには use client がありません。フォームの action に Server Function を渡しています。ビルドはどうなりますか。

この問題を解くこのテーマの問題 3 問