ChatGPTと共にNext.jsで簡易的な掲示板アプリの作る.
- Published on
- Authors
-
- Author
- Masaki Hayashi
- twitter @mh_poteto
-
この記事ではChatGPTを利用して、React、Typescript、そしてNext.jsを使って掲示板アプリを作成する方法について説明します。
この記事を作成するにあたって作成したプロンプトは下記のようになります。
次で与えられたテーマ、技術、目次で技術記事を書いてください。
テーマ
- Next.jsで掲示板アプリの作り方
技術
- React
- Typescript
- Next.js
また、記事を書く際には、以下のルールを必ず遵守してください。
- フォーマットはマークダウンで記載すること
- できるだけ最新の技術を用いること
- 記事内ではソースコードを多めに書くこと
- ソースコードの説明をすること
目次
- 掲示板アプリとは何か?
- 環境の設定
- フロントエンドの作成
- コンポーネントの作成
- ページの作成
- APIの作成
- バックエンドの作成
- APIの作成
- APIのテスト
- データベースの作成
- バックエンドとフロントエンドの連携
- データの取得
- データの投稿
- まとめ
環境の設定
まず最初に、以下のコマンドを使用して、Next.jsプロジェクトを作成します。
npm create-next-app bulletin-app
その後、必要な依存関係をインストールします。
npm install react react-dom next typescript
フロントエンドの作成
コンポーネントの作成
まず、掲示板アプリのフロントエンドで使用するコンポーネントを作成します。ここでは、components
というディレクトリを作成し、その中にMessageList
というコンポーネントを作成します。MessageList
コンポーネントは、メッセージのリストを表示するためのものです。
import React from 'react';
interface Props {
messages: string[];
}
const MessageList: React.FC<Props> = ({ messages }) => (
<ul>
{messages.map((message) => (
<li key={message}>{message}</li>
))}
</ul>
);
export default MessageList;
ページの作成
次に、pages
ディレクトリに、index.tsx
というファイルを作成します。index.tsx
ファイルは、掲示板アプリのトップページとして機能します。以下のようなコードを追加します。
import React, { useState } from 'react';
import MessageList from '../components/MessageList';
const HomePage: React.FC = () => {
const [messages, setMessages] = useState<string[]>([]);
const handleFormSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
const formData = new FormData(event.currentTarget);
const message = formData.get('message') as string;
setMessages((prevMessages) => [...prevMessages, message]);
};
return (
<div>
<form onSubmit={handleFormSubmit}>
<input name="message" type="text" />
<button type="submit">Post Message</button>
</form>
<MessageList messages={messages} />
</div>
);
};
export default HomePage;
このページでは、ユーザーがメッセージを投稿できるフォームを表示し、投稿されたメッセージのリストをMessageList
コンポーネントで表示しています。
APIの作成
バックエンドの作成
次に、掲示板アプリのバックエンドを作成します。まず、api
というディレクトリを作成し、その中にmessages.ts
というファイルを作成します。このファイルでは、メッセージを管理するためのAPIを実装します。
let messages: string[] = [];
export const getMessages = (): string[] => {
return messages;
};
export const addMessage = (message: string): void => {
messages.push(message);
};
messages.ts
ファイルでは、messages
という配列にメッセージを格納し、getMessages
関数でメッセージの一覧を返し、addMessage
関数で新しいメッセージを配列に追加します。
APIの作成
次に、pages/api
ディレクトリに、messages.ts
というファイルを作成します。このファイルでは、GET
リクエストに対応するgetMessages
関数と、POST
リクエストに対応するaddMessage
関数を実装します。
import { NextApiRequest, NextApiResponse } from 'next';
import { addMessage, getMessages } from '../../api/messages';
export default (req: NextApiRequest, res: NextApiResponse) => {
switch (req.method) {
case 'GET':
res.status(200).json(getMessages());
break;
case 'POST':
const { message } = req.body;
addMessage(message);
res.status(200).send('Message added successfully');
break;
default:
res.status(405).end();
break;
}
};
このファイルでは、switch
文を使用して、GET
リクエストとPOST
リクエストを処理します。GET
リクエストの場合は、getMessages
関数を呼び出してメッセージの一覧を返し、POST
リクエストの場合は、リクエストボディからメッセージを取得し、addMessage
関数で配列に追加します。
データベースの作成
ここまでで、APIの実装が完了しました。しかし、現在の実装では、メッセージがサーバーのメモリに格納されているため、サーバーを再起動すると、メッセージが消えてしまいます。そこで、データベースを使って、メッセージを永続化するように改善しましょう。
まず、postgres
というデータベースを使用するために、pg
というパッケージをインストールします。
npm install pg
npm install --save-dev @types/pg
次に、.env.local
ファイルを作成し、そのファイル内にデータベースに接続するための情報を設定します。
DATABASE_URL=postgresql://postgres:password@localhost:5432/nextjs_board
ここで、DATABASE_URL
には、postgresql://ユーザー名:パスワード@ホスト名:ポート番号/データベース名
という形式で、データベースに接続するためのURLを指定します。
次に、lib/db.ts
というファイルを作成し、データベースに接続するための関数を実装します。
import { Pool } from 'pg';
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
ssl: process.env.NODE_ENV === 'production',
});
export const query = (text: string, params?: any[]) => {
return pool.query(text, params);
};
このファイルでは、pg.Pool
を使用して、データベースに接続します。process.env.DATABASE_URL
を使用して、.env.local
ファイルで設定したURLを取得します。また、ssl
オプションをtrue
に設定することで、本番環境ではSSLを使用して通信するようにします。
メッセージの永続化
次に、messages.ts
ファイルを修正して、データベースにメッセージを保存するようにします。
import { query } from "../lib/db"
import Message from "./message";
export const getMessages = async (): Promise<Message[]> => {
const result = await query('SELECT * FROM messages');
const messages: Message[] = []
for (var i = 0; i < result.rows.length; i++) {
messages.push({
id: i,
message: result.rows[i].message,
date: result.rows[i].timestamp,
userName: result.rows[i].user_name,
})
}
return messages.sort((a, b) => a.id > b.id ? -1 : 0);
};
export const addMessage = async (message: string, userName: string): Promise<void> => {
const timestamp = new Date().toLocaleString();
await query('INSERT INTO messages VALUES ($1, $2, $3)', [message, userName, timestamp]);
};
その際に、下記のmessage.ts
ファイルを追加します。
export default interface Message {
id: number;
message: string;
date: string;
userName: string;
}
このファイルでは、query
関数を使用して、messages
テーブルからメッセージを取得するgetMessages
関数と、messages
テーブルにメッセージを挿入するaddMessage
関数を実装しています。
バックエンドとフロントエンドの連携
ここまでで、バックエンドのAPIと、データベースの設定が完了しました。次に、フロントエンドとバックエンドを連携するためのコードを書いていきます。
まず、pages/api/messages/index.ts
を以下のように修正します。
import { NextApiRequest, NextApiResponse } from 'next';
import { addMessage, getMessages } from '../../../lib/messages';
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method === 'GET') {
const messages = await getMessages();
res.status(200).json(messages);
} else if (req.method === 'POST') {
const message = req.body.message;
await addMessage(message);
res.status(200).send('Message added successfully');
}
}
このファイルでは、getMessages
関数とaddMessage
関数をインポートし、GET
リクエストとPOST
リクエストに対して、適切なレスポンスを返します。
次に、pages/index.tsx
を以下のように修正します。
import Message from '@/api/message';
import { useState, useEffect } from 'react';
import styles from '../styles/Home.module.css';
interface Post {
userName: string;
content: string;
postTime: string;
}
const Home = () => {
const [messages, setMessages] = useState<Message[]>([]);
const [userName, setUserName] = useState('');
const [content, setContent] = useState('');
useEffect(() => {
fetch('/api/messages')
.then((res) => res.json())
.then((data) => setMessages(data));
}, []);
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (content.length < 1 || userName.length < 1) {
return;
}
fetch('/api/messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
message: content,
userName: userName,
}),
})
.then((res) => res.text())
.then((data) => {
setContent('');
setUserName('');
fetch('/api/messages')
.then((res) => res.json())
.then((data) => setMessages(data));
});
};
const handleUserNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setUserName(event.target.value);
};
const handleContentChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
setContent(event.target.value);
};
return (
<div className={styles.container}>
<h1>掲示板</h1>
<form onSubmit={handleSubmit}>
<div className="form-group">
<label htmlFor="userName">ユーザー名</label><br />
<input type="text" className="form-control" id="userName" value={userName} onChange={handleUserNameChange} required />
</div>
<div className="form-group">
<label htmlFor="content">投稿内容</label><br />
<textarea className="form-control" id="content" value={content} onChange={handleContentChange} required />
</div>
<button type="submit" className="btn btn-primary">投稿する</button>
</form>
<div className="post-list">
{messages.map((data, index) => (
<div className="post" key={index}>
<div className="post-header">
<h2>{data.userName}</h2>
<p>{data.date}</p>
</div>
<div className="post-content">
<p>{data.message}</p>
</div>
</div>))}
</div>
</div>
);
};
export default Home;
このファイルでは、useState
フックを使用して、messages
とnewMessage
という状態を管理しています。useEffect
フックを使用して、ページがロードされたときに/api/messages
にGET
リクエストを送信し、取得したメッセージをmessages
ステートにセットしています。
handleNewMessage
関数は、新しいメッセージを送信するために使用されます。フォームが送信されたときに、/api/messages
にPOST
リクエストを送信して、新しいメッセージを追加します。リクエストが成功した場合、setNewMessage
関数を使用して、入力フィールドをクリアし、/api/messages
にGET
リクエストを送信して、更新されたメッセージリストを取得し、messages
ステートにセットします。
まとめ
この記事では、Next.jsを使用して掲示板アプリを作成する方法を説明しました。React、TypeScript、およびNext.jsを使用して、フロントエンドとバックエンドを構築し、データベースとの通信を設定しました。最後に、Vercelを使用してアプリをデプロイしました。
この記事を通じて、Next.jsの基本的な概念と、ReactとTypeScriptの基礎を学ぶことができました。Next.jsは、Reactアプリケーションの構築に役立つ強力なフレームワークであり、高速な開発サイクルを実現することができます。