目標
- Next.jsでフォームを扱う方法を学ぶ。
-
react-hook-form
を使って効率的にフォームを作成する。 - NextAuth.jsで認証(Googleログインなど)を統合する。
- 管理者用のページを保護する。
1. フォームライブラリの導入
フォーム処理を簡単にするために、react-hook-form
を使用します。
インストール:
ターミナルで実行:
npm install react-hook-form
2. 投稿追加フォームの作成
Supabaseに投稿を追加するフォームを実装します。
app/add-post/page.tsx
の作成:
'use client';
import { useForm } from 'react-hook-form';
import { supabase } from '../../lib/supabase';
type FormData = {
title: string;
content: string;
};
export default function AddPost() {
const { register, handleSubmit, reset } = useForm<FormData>();
const onSubmit = async (data: FormData) => {
const { error } = await supabase.from('posts').insert([data]);
if (error) {
console.error('エラー:', error);
} else {
alert('投稿が追加されました!');
reset();
}
};
return (
<div className="max-w-2xl mx-auto p-6">
<h1 className="text-3xl font-bold text-blue-600 mb-6">新しい投稿を追加</h1>
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
<div>
<label className="block text-gray-700">タイトル</label>
<input
{...register('title', { required: true })}
className="w-full p-2 border rounded"
placeholder="投稿のタイトル"
/>
</div>
<div>
<label className="block text-gray-700">内容</label>
<textarea
{...register('content', { required: true })}
className="w-full p-2 border rounded"
placeholder="投稿の内容"
rows={5}
/>
</div>
<button type="submit" className="bg-blue-500 text-white p-2 rounded hover:bg-blue-600">
投稿する
</button>
</form>
</div>
);
}
注意:
-
'use client'
を追加して、クライアント側で動作するコンポーネントに指定。
3. NextAuth.jsでの認証設定
Googleログインを追加して、認証を導入します。
インストール:
npm install next-auth
app/api/auth/[...nextauth]/route.ts
の作成:
import NextAuth from 'next-auth';
import GoogleProvider from 'next-auth/providers/google';
export const authOptions = {
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID || '',
clientSecret: process.env.GOOGLE_CLIENT_SECRET || '',
}),
],
};
const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };
環境変数の設定:
.env.local
に以下を追加:
GOOGLE_CLIENT_ID=あなたのGoogleクライアントID
GOOGLE_CLIENT_SECRET=あなたのGoogleクライアントシークレット
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=ランダムな文字列(例:openssl rand -base64 32で生成)
Google設定:
- Google Cloud ConsoleでOAuth 2.0クライアントを作成し、IDとシークレットを入手。
4. 認証状態の管理と保護
ログイン状態を確認し、管理者ページを保護します。
ログイン状態の表示:
app/layout.tsx
を編集してヘッダーにログイン状態を追加:
import './globals.css';
import Link from 'next/link';
import { auth } from 'next-auth';
import { signIn, signOut } from 'next-auth/react';
export const metadata = {
title: 'Next.js 2025シリーズ',
description: '2025年のウェブ開発を学ぶ',
};
export default async function RootLayout({ children }) {
const session = await auth();
return (
<html lang="ja">
<body className="font-sans antialiased">
<header className="bg-blue-800 text-white p-4">
<nav className="max-w-4xl mx-auto flex justify-between items-center">
<Link href="/" className="text-xl font-bold">ホーム</Link>
<div className="space-x-4">
<Link href="/about" className="hover:underline">About</Link>
<Link href="/add-post" className="hover:underline">投稿追加</Link>
{session ? (
<>
<span>{session.user?.name}</span>
<button onClick={() => signOut()} className="hover:underline">ログアウト</button>
</>
) : (
<button onClick={() => signIn('google')} className="hover:underline">Googleでログイン</button>
)}
</div>
</nav>
</header>
<main>{children}</main>
<footer className="bg-gray-200 p-4 text-center text-gray-600">
© 2025 Next.js学習シリーズ
</footer>
</body>
</html>
);
}
ページの保護:
app/add-post/page.tsx
を保護:
'use client';
import { useForm } from 'react-hook-form';
import { supabase } from '../../lib/supabase';
import { useSession } from 'next-auth/react';
import { redirect } from 'next/navigation';
type FormData = {
title: string;
content: string;
};
export default function AddPost() {
const { data: session } = useSession();
if (!session) {
redirect('/api/auth/signin');
}
const { register, handleSubmit, reset } = useForm<FormData>();
const onSubmit = async (data: FormData) => {
const { error } = await supabase.from('posts').insert([data]);
if (error) {
console.error('エラー:', error);
} else {
alert('投稿が追加されました!');
reset();
}
};
return (
<div className="max-w-2xl mx-auto p-6">
<h1 className="text-3xl font-bold text-blue-600 mb-6">新しい投稿を追加</h1>
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
<div>
<label className="block text-gray-700">タイトル</label>
<input
{...register('title', { required: true })}
className="w-full p-2 border rounded"
placeholder="投稿のタイトル"
/>
</div>
<div>
<label className="block text-gray-700">内容</label>
<textarea
{...register('content', { required: true })}
className="w-full p-2 border rounded"
placeholder="投稿の内容"
rows={5}
/>
</div>
<button type="submit" className="bg-blue-500 text-white p-2 rounded hover:bg-blue-600">
投稿する
</button>
</form>
</div>
);
}
実践:認証付きブログ
- フォーム: ログインしたユーザーが投稿を追加可能。
- 認証: Googleログインでアクセスを管理。
- 保護: 未ログインの場合は投稿追加ページにアクセス不可。
確認:
-
/add-post
にアクセスし、ログインを試みて投稿を追加。
エピソード7の終了
- フォームと認証をNext.jsに統合しました。
- ユーザーインタラクションを強化しました。
次回のエピソード:パフォーマンスとSEOを最適化し、ウェブサイトを完成させます。
この記事が役に立ったと思ったら、ぜひ「いいね」を押して、ストックしていただければ嬉しいです!次回のエピソードもお楽しみに!