6.
チャットボット(フロントエンド 1)
App Router
App Routerとは
App Routerは、Next.js 13から導入された新しいルーティングシステムで、従来のファイルベースのルーティングより柔軟で強力な機能となりました。
App Routerの主要機能
ファイルベースのルーティング
Next.jsではファイル構造に基づいて自動的にルーティングされます。 appディレクトリ内のファイルとフォルダがそのままルートになります。
Layoutとページの分離
レイアウト「app/layout.tsx」を定義することで、各ページ間で共有レイアウトを利用できます。
Server ComponentsとClient Components
Next.jsでは、Server ComponentsとClient Componentsの両方をサポートします。SSR(サーバー側でレンダリングされるコンポーネント)とCSR(クライアント側で動作するコンポーネント)を使い分けることができます。
トップページのルーティング
App Routerでは「app」ディレクトリの中に「page.*」ファイルが存在すると自動ルーティングされます。
- 拡張子の部分は「jsx」「tsx」
レイアウトとコンポーネント
Next.jsではデフォルトでは「layout.tsx」がレイアウト、「page.tsx」がページコンポーネントになっています。
トップページ
URI | レイアウト | ページコンポーネント |
---|---|---|
http://localhost:3000/ | app/layout.tsx | app/page.tsx |

フロントエンド作成
ファイル構成
my-app/
├── app/
│ ├── api/
│ │ └── chat/
│ │ └── route.ts
│ └── page.tsx
├── styles/
│ └── globals.css
├── .env.local
├── tailwind.config.js
├── tsconfig.json
└── package.json
レイアウト
レイアウト修正
レイアウトファイル「app/layout.tsx」を開きます。

children
Next.jsのレイアウトファイルは、{children} の部分に各ページコンポーネントが表示されるように設計されています。
app/layout.tsx
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body className="container">{children}</body>
</html>
);
}
Metadata修正
「metadata」 の「title」「description」を修正します。
app/layout.tsx
// Metadata修正
export const metadata: Metadata = {
title: "Gemini Chatbot",
description: "Gemini APIを利用したチャットボットアプリです。",
};
CSS修正
「app/layout.tsx」のデフォルトは、同階層の「globals.css」を読み込んでいます。
app/layout.tsx
import type { Metadata } from "next";
// globals.css 読み込み
import "./globals.css";
「app/globals.css」を開きます。

余分なCSSを削除し、TailwindCSSだけにします。
@tailwind base;
@tailwind components;
@tailwind utilities;
動作確認
ページタイトルや説明文が変更されました。このように各ページの共通部分(HTMLの基本構造やナビゲーションなど)はレイアウトで管理します。

トップページ修正
今回のページはCSRに対応したClient Componentで作成します。
ページコンポーネントを開く
トップページのコンポーネント「app/page.tsx」を開きます。

use client
先頭にuse clientを追加してClient Componentにします。
app/page.tsx
// 追加:Client Componentとする
'use client';
import { useState } from "react";
ページコンポーネント修正
JSXを修正します。
app/page.tsx
'use client';
export default function Home() {
return (
<main className="flex flex-col justify-center">
<h1 className="text-2xl p-5">Gemini Chatbot</h1>
</main>
);
}
動作確認
トップページが変更されました。

メッセージ入力処理
フォーム作成
メッセージの入力フォームを作成します。
app/page.tsx
'use client';
export default function Home() {
return (
<main className="flex flex-col justify-center">
<div className="bg-white shadow-md p-4 z-10">
<h1 className="text-2xl p-5">Gemini Chatbot</h1>
<div className="flex">
<input
type="text"
className="w-full p-2 border border-gray-300 rounded-l mr-0"
placeholder="Type your message..."
/>
<button className="w-1/6 bg-blue-500 text-white p-2 rounded-r">
Send
</button>
</div>
</div>
</main>
);
}
フォーム確認
入力フォームが表示されるか確認します。

イベント処理
テキストボックスに入力したデータを設定するようにします。
データ定義
入力データの定義します。
app/page.tsx
export default function Home() {
// 入力データ定義
const [inputMessage, setInputMessage] = useState<string>('');
...
}
イベントハンドラー作成
changeMessageHandler() を追加します。
app/page.tsx
export default function Home() {
const [inputMessage, setInputMessage] = useState<string>('');
const changeMessageHandler = (e: React.ChangeEvent<HTMLInputElement>) => {
};
....
}
テキストボックスの値を inputMessage() に設定します。
app/page.tsx
export default function Home() {
const [inputMessage, setInputMessage] = useState<string>('');
const changeMessageHandler = (e: React.ChangeEvent<HTMLInputElement>) => {
// デバック用
console.log(e.target.value);
// テキストボックスのデータを inputMessage に設定
setInputMessage(e.target.value);
};
....
}
イベント追加
inputタグにonChangeイベントを追加し、値には「inputMessage」を設定します。
app/page.tsx
export default function Home() {
...
return (
<main className="flex flex-col justify-center">
<div className="bg-white shadow-md p-4 z-10">
<h1 className="text-2xl p-5">Gemini Chatbot</h1>
<div className="flex">
<input
onChange={changeMessageHandler}
value={inputMessage}
type="text"
className="w-full p-2 border border-gray-300 rounded-l mr-0"
placeholder="Type your message..."
/>
<button className="w-1/6 bg-blue-500 text-white p-2 rounded-r">
Send
</button>
</div>
</div>
</main>
);
}
動作確認
テキストボックスに入力するたびに、メッセージがコンソール表示されるか確認します。

クリックイベント
ボタンをクリックしたら、メッセージをAPIに送信するようにします。
イベントハンドラー追加
ボタンクリックのイベントハンドラーを作成します。
app/page.tsx
export default function Home() {
...
const sendHandler = async (e: React.MouseEvent<HTMLButtonElement>) => {
if (inputMessage.trim() === '') return;
setInputMessage('');
};
...
}
イベント追加
buttonタグにonClickイベントを追加します。
app/page.tsx
export default function Home() {
...
return (
<main className="flex flex-col justify-center">
<div className="bg-white shadow-md p-4 z-10">
<h1 className="text-2xl p-5">Gemini Chatbot</h1>
<div className="flex">
<input
onChange={changeMessageHandler}
value={inputMessage}
type="text"
className="w-full p-2 border border-gray-300 rounded-l mr-0"
placeholder="Type your message..."
/>
<button className="w-1/6 bg-blue-500 text-white p-2 rounded-r"
onClick={sendHandler}>
Send
</button>
</div>
</div>
</main>
);
}
動作確認
【Send】ボタンをクリックして、テキストボックスがブランクになるか確認します。