1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

2025年人気No.1のNext.jsで、最新ツールとウェブを作る! | エピソード7 フォームと認証

Posted at

目標

  • 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を最適化し、ウェブサイトを完成させます。


この記事が役に立ったと思ったら、ぜひ「いいね」を押して、ストックしていただければ嬉しいです!次回のエピソードもお楽しみに!

1
0
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?