はじめに
Next.jsのApp Routerを使ってブログアプリ(最小限の構成)を作った🔰
App Routerの新しい機能を使ったり、CRUD操作をしたりと勉強になったので備忘録を残す😊
作ったもの
✅ブログの投稿を作成、編集、削除ができるアプリを作った。
投稿の一覧
投稿を一覧表示する。
投稿の作成
「タイトル」「本文」を入力して投稿を作成する。
投稿の編集
「タイトル」「本文」を編集する。
投稿の削除
削除ボタンをクリックして削除する。
フォルダ構成
使用したApp Router周りの機能
- App Routerのルーティング
- サーバーコンポーネント、クライアントコンポーネント
- Server Actions
App Routerって何?
準備
使用する手法・技術の紹介
事前にインストールしておくもの
- Node.js
- npm
- Next.js
- Prisma
-
サーバー(何でもOK)
例:SQLite、ローカルPCにインストールしたMySQL、ネットワーク上のサーバーなど
今からインストールするもの
- Prisma
Prismaをインストールする
prismaをインストールする。
npm install prisma
Prisma Clientをインストールする。
(プログラムからデータベースにアクセスするために必要)
npm install @prisma/client
Prismaを初期化する
npx prisma init
これで「prismaフォルダ」と「.envファイル」ができる。
データベースを新規作成
✅これからPrismaでデータベース操作をするので、事前に手動でデータベースそのものを用意する。
今回はMySQLのデータベースを作ってみる。
(PCにインストール済みのMAMPにMySQLが備わっていたのでそれを使う)
【手順1】phpMyAdminにアクセス
MAMPを起動しphpMyAdminを開く。
【手順2】データベースを新規作成
今回は「nextjs-blog」という名前のデータベースを作成する。
prisma/schema.prismaの設定
デフォルトは以下のようになっている。
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
使用するデータベースに合わせてproviderを変更する。
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mysql" // ✅変更
url = env("DATABASE_URL")
}
.envの設定
デフォルトは以下のようになっている。
DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"
自分のデータベースの情報に書き換える。
// ✅変更
DATABASE_URL="mysql://id:pass@localhost:port番号/DB名?schema=public"
例:MAMPの場合はデフォルトだと以下のようになる。
DATABASE_URL="mysql://root:root@localhost:3306/nextjs-blog?schema=public"
MAMPの場合のポート番号の確認方法
テーブルを新規作成
以下の手順でテーブルが作れる。
【手順1】prisma/schema.prisma にテーブル定義を書く
以下のようにmodelを書けばOK。
今回はPostsテーブルを作成する。
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}
// ✅追記
model Posts {
id Int @id @default(autoincrement())
title String
body String
createdAt DateTime @default(now())
updatedAt DateTime?
}
【手順2】マイグレートする
コマンドを実行するだけでOK。
npx prisma migrate dev --name init
成功した画面
✅実行結果
phpMyAdminを見ると、データベース「nextjs-blog」にテーブル「Posts」ができている。
【手順1】Server Actionsで使う関数を準備
やりたいこと
✅今回はApp Routerの新機能「Server Actions」を使いたい。
Server Actionstとは?
クライアントからバックエンドの関数を呼び出せる機能✨
具体的にはフォーム送信時などにバックエンドの関数を呼び出せる。
具体的には以下の処理をするバックエンドの関数をフォーム送信時に呼び出したい。
- 投稿の作成
- 投稿の削除
- 投稿の更新
【補足】投稿の取得はServer Actionsでなくてもいい
(疑問)
「投稿の取得」も作成、削除、編集と同様CRUD操作の一部。
投稿の取得もServer Actionsに含めた方がいい?💭
(答え)
投稿の取得はクライアントから呼び出す関数ではないのでServer Actionsに含めなくていい。
→サーバー側の初期レンダリングで呼び出す。
【手順1-1】データベース接続用モジュールの作成
データベース接続するためのファイルを作っておく。
✅PrismaClientを生成することでデータベース操作ができる。
→今後はこのファイルをインポートするだけでデータベース操作ができる。
src/app/lib/prisma.js
/**
* Prisma Clientをインポートします。
*/
import { PrismaClient } from "@prisma/client";
let prisma;
/**
* 環境に応じてPrismaClientのインスタンスを作成します。
* 本番環境では新しいインスタンスを作成し、それ以外の環境ではグローバルなインスタンスを再利用します。
*/
if (process.env.NODE_ENV === "production") {
prisma = new PrismaClient();
} else {
if (!global.prisma) {
global.prisma = new PrismaClient();
}
prisma = global.prisma;
}
export default prisma;
【手順1-2】関数を作る
✅1つのファイルに作成、削除、編集の関数をまとめて定義しておく。
src/app/lib/posts.js
// ✅Server Actions
"use server";
// ✅データベース接続用モジュール
import prisma from "@/app/lib/prisma";
/**
* 新規投稿をデータベースに作成します。
* @async
* @function addPost
* @param {Object} data - 新規投稿のデータ
*/
export const addPost = async (data) => {
// 入力値を取得
const title = data.get("title");
const body = data.get("body");
// データベースに1レコード作成
await prisma.posts.create({
data: {
title,
body,
},
});
};
/**
* 指定されたIDの投稿を削除します。
*
* @param {FormData} data - フォームデータ。'id'フィールドには削除する投稿のIDが含まれている必要があります。
* @returns {Promise<void>} 削除操作が完了すると解決するPromise。
*/
export const deletePost = async (data) => {
// 入力値を取得
const id = data.get("id");
// データベースから1レコード削除
await prisma.posts.delete({
where: {
id: parseInt(id),
},
});
};
/**
* 指定されたIDの投稿を更新します。
*
* @param {FormData} data - フォームデータ。'id'フィールドには更新する投稿のIDが含まれている必要があります。
* @returns {Promise<void>} 更新操作が完了すると解決するPromise。
*/
export const updatePost = async (data) => {
// 入力値を取得
const id = data.get("id");
const title = data.get("title");
const body = data.get("body");
// データベースのレコードを更新
await prisma.posts.update({
where: {
id: parseInt(id),
},
data: {
title: title,
body: body,
},
});
};
【解説】✅Server Actions
// ✅Server Actions
"use server";
Server Actionsで使う関数は「私はクライアントから呼び出せる関数だよ〜」な状態にしておく必要がある。
→ファイルの先頭に"use server";
をつけるだけでOK!
【解説】✅データベース接続用モジュール
// ✅データベース接続用モジュール
import prisma from "@/app/lib/prisma";
【手順1-1】で作成したファイルをインポートしている。
これだけでデータベース操作が可能になる。
【解説】投稿の作成、削除、編集
/**
* 新規投稿をデータベースに作成します。
* @async
* @function addPost
* @param {Object} data - 新規投稿のデータ
*/
export const addPost = async (data) => {
// 入力値を取得
const title = data.get("title");
const body = data.get("body");
// データベースに1レコード作成
await prisma.posts.create({
data: {
title,
body,
},
});
};
/**
* 指定されたIDの投稿を削除します。
*
* @param {FormData} data - フォームデータ。'id'フィールドには削除する投稿のIDが含まれている必要があります。
* @returns {Promise<void>} 削除操作が完了すると解決するPromise。
*/
export const deletePost = async (data) => {
// 入力値を取得
const id = data.get("id");
// データベースから1レコード削除
await prisma.posts.delete({
where: {
id: parseInt(id),
},
});
};
/**
* 指定されたIDの投稿を更新します。
*
* @param {FormData} data - フォームデータ。'id'フィールドには更新する投稿のIDが含まれている必要があります。
* @returns {Promise<void>} 更新操作が完了すると解決するPromise。
*/
export const updatePost = async (data) => {
// 入力値を取得
const id = data.get("id");
const title = data.get("title");
const body = data.get("body");
// データベースのレコードを更新
await prisma.posts.update({
where: {
id: parseInt(id),
},
data: {
title: title,
body: body,
},
});
};
Prismaで単純なデータベース操作をしているだけ。
Prismaの話なので詳細は割愛する。
【手順2】全体のレイアウト
✅layout.jsで全ページ共通のレイアウトを定義する。
layout.jsとは?
共通のレイアウトやメタデータなどを定義するファイル。
App Router専用。
【手順2-1】適当なレイアウトを作成
src/app/layout.js
import { Inter } from 'next/font/google'
import './globals.css'
const inter = Inter({ subsets: ['latin'] })
export const metadata = {
title: 'ブログアプリ',
description: 'ブログアプリのデモです。',
}
export default function RootLayout({ children }) {
return (
<html lang="ja">
<body className={inter.className}>{children}</body>
</html>
)
}
メタデータだけ書き換えた。
好みに合わせて自由に編集してOK✨
【手順3】投稿一覧ページ
✅「投稿一覧」と「新規作成ボタン」を表示するページ。
完成イメージ
【手順3-1】ページを作る
✅URL「/」でアクセスできる投稿一覧ページを作る。
src/app/page.jsx
import Link from 'next/link';
import prisma from "@/app/lib/prisma";
// ✅投稿データ一覧のコンポーネント
import PostList from "./(components)/PostList";
// ✅このページをSSRにする
export const dynamic = 'force-dynamic'
/**
* 投稿のリストと新規投稿作成へのリンク
* @async
* @function Page
* @returns {JSX.Element} 投稿一覧と新規作成リンクを含むReactコンポーネント
*/
const Page = async () => {
// ✅投稿データのリスト
const posts = await prisma.posts.findMany();
return (
<div className="m-8">
<h1 className="text-2xl font-bold mb-4">投稿一覧</h1>
<PostList posts={posts} />
<Link href="/create" className="inline-block bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-700">新規作成</Link>
</div>
);
};
export default Page;
【解説】✅投稿データ一覧のコンポーネント
// ✅投稿データ一覧のコンポーネント
import PostList from "./(components)/PostList";
以下の部分を表示するコンポーネント。
【手順3-2】で作る。
【補足】コンポーネントは必ず分ける
コンポーネントを分けないとサーバーコンポーネント、クライアントコンポーネントの使い分けができない。
(問題点)
-
サーバーコンポーネント、クライアントコンポーネントはそれぞれできないことがある。
- 例えば…
- サーバーコンポーネントではuseStateが使えない。
- クライアントコンポーネントでは直接Prismaを使ったデータベース操作はできない。
- もし1つのファイルにまとめて書くとサーバーコンポーネント、クライアントコンポーネントどちらかの処理しか書けない💦
【解説】✅このページをSSRにする
// ✅このページをSSRにする
export const dynamic = 'force-dynamic'
これがないとSSGになってしまう。
(問題点)
SSGのままだと投稿を作成や編集をしても一覧データが更新されない💦
具体的にはこの部分がずっと古いまま。
(解決)
SSRにすることで常に最新のデータが取得できる✨
ちなみに「SSRにする他の方法」や「ISRで解決する方法」もある。
【解説】✅投稿データのリスト
// ✅投稿データのリスト
const posts = await prisma.posts.findMany();
以下の部分のデータを取得する。
(ここで取得したデータは【手順3-2】で作るPostListコンポーネントに渡す)
【手順3-2】投稿一覧を表示するコンポーネントを作る
✅投稿一覧を表示するPostListコンポーネントを作る。
具体的には以下の部分。
src/app/(components)/PostList.jsx
// ✅クライアントコンポーネント
"use client";
import { useState } from "react";
// ✅投稿コンポーネント
import Post from "./Post";
// ✅投稿削除関数
import { deletePost } from "@/app/lib/posts";
/**
* 投稿のリストを表示
* @function PostList
* @param {Object} props - プロパティオブジェクト
* @param {Array} props.posts - 投稿データの配列
* @returns {JSX.Element} 投稿リストを含むReactコンポーネント
*/
const PostList = (props) => {
// 投稿データのリスト
const [posts, setPosts] = useState(props.posts);
/**
* ✅投稿データを削除
* @function handleDelete
* @param {Object} data - 削除する投稿データ
*/
const handleDelete = (data) => {
deletePost(data); // データベースから削除
const id = parseInt( data.get('id') ); // 数値に変換
setPosts(posts.filter((post) => post.id !== id)); // 画面から削除
};
return (
<table className="mt-8 w-full table-auto">
<tbody>
{posts.map((post) => (
<Post
key={post.id}
post={post}
handleDelete={handleDelete}
/>
))}
</tbody>
</table>
);
};
export default PostList;
【解説】✅クライアントコンポーネント
// ✅クライアントコンポーネント
"use client";
useStateを使うためにクライアントコンポーネントにした。
→useStateで投稿一覧の状態を管理して、投稿が減ると即時反映したい。
イメージ
【他の方法】revalidatePath関数を使う
useStateで投稿一覧を状態管理しなくても、削除後にrevalidatePath関数を実行することで最新データを取得しなおすこともできる。(ISR)
この方法だとPostListコンポーネントをクライアントコンポーネントではなくサーバーコンポーネントのままにしておける。
【解説】✅投稿コンポーネント
// ✅投稿コンポーネント
import Post from "./Post";
投稿1件を表示するコンポーネント。
【手順3-3】で作る。
【解説】✅投稿削除関数
// ✅投稿削除関数
import { deletePost } from "@/app/lib/posts";
投稿を削除(テーブルから1レコード削除)する関数。
deletePost関数は以下のファイルで定義済み。
【再掲】src/app/lib/posts.js
/**
* 指定されたIDの投稿を削除します。
*
* @param {FormData} data - フォームデータ。'id'フィールドには削除する投稿のIDが含まれている必要があります。
* @returns {Promise<void>} 削除操作が完了すると解決するPromise。
*/
export const deletePost = async (data) => {
// 入力値を取得
const id = data.get("id");
// データベースから1レコード削除
await prisma.posts.delete({
where: {
id: parseInt(id),
},
});
};
【解説】✅投稿データを削除
/**
* ✅投稿データを削除
* @function handleDelete
* @param {Object} data - 削除する投稿データ
*/
const handleDelete = (data) => {
deletePost(data); // データベースから削除
const id = parseInt( data.get('id') ); // 数値に変換
setPosts(posts.filter((post) => post.id !== id)); // 画面から削除
};
投稿の削除(テーブルから1レコード削除)を呼び出し、画面からも削除する関数。
【手順3-3】投稿1つを表示するコンポーネントを作る
✅投稿1つを表示するPostコンポーネントを作る。
具体的には以下の部分。
src/app/(components)/Post.jsx
// ✅クライアントコンポーネント
"use client";
import Link from 'next/link'
/**
* ✅単一の投稿データを表示
* @function Post
* @param {Object} props - プロパティオブジェクト
* @param {Object} props.post - 投稿データ
* @param {Function} props.handleDelete - 投稿削除のハンドラ関数
* @returns {JSX.Element} 投稿データを表示するReactコンポーネント
*/
const Post = ({post, handleDelete}) => {
return (
<tr key={post.id} className="border-t border-gray-200">
<td className="px-4 py-2">{post.id}</td>
<td className="px-4 py-2">{post.title}</td>
<td className="px-4 py-2">{post.body}</td>
<td className="px-4 py-2 flex">
{/* 編集ボタン */}
<Link href={`edit/${post.id}`} className="text-white bg-blue-500 hover:bg-blue-700 px-2 py-1 rounded">編集</Link>
{/* 削除ボタン */}
<form action={handleDelete}>
<input type="hidden" name="id" value={post.id} />
<button
className="text-white bg-red-500 hover:bg-red-700 px-2 py-1 rounded ml-2"
>
削除
</button>
</form>
</td>
</tr>
);
};
export default Post;
【解説】✅クライアントコンポーネント
// ✅クライアントコンポーネント
"use client";
親コンポーネント(PostList)がクライアントコンポーネントのため、Postもクライアントコンポーネントにした。
(クライアントコンポーネントからサーバーコンポーネントはインポートできないため)
【解説】✅単一の投稿データを表示
/**
* ✅単一の投稿データを表示
* @function Post
* @param {Object} props - プロパティオブジェクト
* @param {Object} props.post - 投稿データ
* @param {Function} props.handleDelete - 投稿削除のハンドラ関数
* @returns {JSX.Element} 投稿データを表示するReactコンポーネント
*/
const Post = ({post, handleDelete}) => {
return (
<tr key={post.id} className="border-t border-gray-200">
<td className="px-4 py-2">{post.id}</td>
<td className="px-4 py-2">{post.title}</td>
<td className="px-4 py-2">{post.body}</td>
<td className="px-4 py-2 flex">
{/* 編集ボタン */}
<Link href={`edit/${post.id}`} className="text-white bg-blue-500 hover:bg-blue-700 px-2 py-1 rounded">編集</Link>
{/* 削除ボタン */}
<form action={handleDelete}>
<input type="hidden" name="id" value={post.id} />
<button
className="text-white bg-red-500 hover:bg-red-700 px-2 py-1 rounded ml-2"
>
削除
</button>
</form>
</td>
</tr>
);
};
投稿1件を表示しているだけ。
具体的には以下を表示している。
-
id、タイトル、本文
<td className="px-4 py-2">{post.id}</td> <td className="px-4 py-2">{post.title}</td> <td className="px-4 py-2">{post.body}</td>
-
編集ボタン
{/* 編集ボタン */} <Link href={`edit/${post.id}`} className="text-white bg-blue-500 hover:bg-blue-700 px-2 py-1 rounded">編集</Link>
- ただのリンク。
- リンク先はidを使って動的に決めている。
- リンク先の編集ページは【手順5】で作る。
-
削除ボタン
{/* 削除ボタン */} <form action={handleDelete}> <input type="hidden" name="id" value={post.id} /> <button className="text-white bg-red-500 hover:bg-red-700 px-2 py-1 rounded ml-2" > 削除 </button> </form>
- Server Actionsを使って、削除ボタンクリック時にhandleDelete関数を呼び出す。
- Server Actionsを使うにはformタグが必須。
- handleDelete関数(【手順3-2】で作った親コンポーネントの関数)が呼ばれると、データベースと画面から投稿が削除される。
- handleDelete関数にidを渡したいため、非表示の<input>タグを入れている。
【手順4】投稿作成ページ
✅「タイトル」「本文」を入力して投稿を作成するページ。
完成イメージ
【手順4-1】ページを作る
✅URL「/create」でアクセスできる投稿作成ページを作る。
src/app/create/page.jsx
import { addPost } from "@/app/lib/posts";
/**
* 新規投稿を作成するためのフォームを表示します。
* @async
* @function Page
* @returns {JSX.Element} 新規投稿作成フォームを含むReactコンポーネント
*/
const Page = async () => {
// ✅投稿の内容を入力するフォーム
return (
<div className="m-10">
<h1 className="text-xl font-bold">投稿作成</h1>
<form className="flex mt-8 flex-col" action={addPost}>
<label htmlFor="title">タイトル:</label>
<input
type="text"
name="title"
className="border mx-4 p-1 w-full text-black"
/>
<label htmlFor="body" className="mt-4">
本文:
</label>
<textarea
name="body"
rows="4"
className="border mx-4 p-1 w-full text-black"
/>
<button
type="submit"
className="bg-blue-600 px-2 py-1 rounded-lg text-sm text-white mx-4 mt-4"
>
作成
</button>
</form>
</div>
);
};
export default Page;
【解説】✅投稿の内容を入力するフォーム
// ✅投稿の内容を入力するフォーム
return (
<div className="m-10">
<h1 className="text-xl font-bold">投稿作成</h1>
<form className="flex mt-8 flex-col" action={addPost}>
省略
</form>
</div>
);
Server Actionsを使って、作成ボタンクリック時にaddPost関数を呼び出す。
addPost関数は以下のファイルで定義済み。
【再掲】src/app/lib/posts.js
/**
* 新規投稿をデータベースに作成します。
* @async
* @function addPost
* @param {Object} data - 新規投稿のデータ
*/
export const addPost = async (data) => {
// 入力値を取得
const title = data.get("title");
const body = data.get("body");
// データベースに1レコード作成
await prisma.posts.create({
data: {
title,
body,
},
});
};
【手順5】投稿編集ページ
✅「タイトル」「本文」を編集するページ。
完成イメージ
【手順5-1】ページを作る
✅URL「/edit/〇〇」でアクセスできる投稿編集ページを作る。
(〇〇には編集したい投稿のidが入る)
src/app/edit/[id]/page.jsx
※[id]は動的なパス(URLの〇〇の部分)を表す。
import prisma from "@/app/lib/prisma";
import { updatePost } from "@/app/lib/posts";
/**
* 指定されたIDの投稿を編集するためのフォームを表示します。
* @async
* @function Page
* @param {Object} params - パラメータオブジェクト
* @param {string} params.id - 編集する投稿のID
* @returns {JSX.Element} 投稿編集フォームを含むReactコンポーネント
*/
const Page = async ({params}) => {
const id = params.id;
// 投稿データを取得
const post = await prisma.posts.findUnique({
where: {
id: parseInt(id),
},
});
// ✅投稿の内容を編集するフォーム
return (
<div className="m-8">
<h1 className="text-2xl font-bold mb-4">投稿編集</h1>
<p>ID: {id}</p>
<form action={updatePost}>
<input type="hidden" name="id" value={post.id} />
<input name="title" type="text" defaultValue={post.title} className="w-full px-3 py-2 placeholder-gray-300 border border-gray-300 rounded-md focus:outline-none focus:ring focus:ring-indigo-100 focus:border-indigo-300 dark:bg-gray-700 dark:text-white dark:placeholder-gray-500 dark:border-gray-600 dark:focus:ring-gray-900 dark:focus:border-gray-500" />
<textarea name="body" defaultValue={post.body} className="w-full px-3 py-2 mt-4 placeholder-gray-300 border border-gray-300 rounded-md focus:outline-none focus:ring focus:ring-indigo-100 focus:border-indigo-300 dark:bg-gray-700 dark:text-white dark:placeholder-gray-500 dark:border-gray-600 dark:focus:ring-gray-900 dark:focus:border-gray-500" />
<button className="mt-4 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-700" >更新</button>
</form>
</div>
);
};
export default Page;
【解説】✅投稿の内容を編集するフォーム
// ✅投稿の内容を編集するフォーム
return (
<div className="m-8">
<h1 className="text-2xl font-bold mb-4">投稿編集</h1>
<p>ID: {id}</p>
<form action={updatePost}>
省略
</form>
</div>
);
Server Actionsを使って、更新ボタンクリック時にupdatePost関数を呼び出す。
updatePost関数は以下のファイルで定義済み。
【再掲】src/app/lib/posts.js
/**
* 指定されたIDの投稿を更新します。
*
* @param {FormData} data - フォームデータ。'id'フィールドには更新する投稿のIDが含まれている必要があります。
* @returns {Promise<void>} 更新操作が完了すると解決するPromise。
*/
export const updatePost = async (data) => {
// 入力値を取得
const id = data.get("id");
const title = data.get("title");
const body = data.get("body");
// データベースのレコードを更新
await prisma.posts.update({
where: {
id: parseInt(id),
},
data: {
title: title,
body: body,
},
});
};
【補足】投稿一覧ページのようにexport const dynamic = 'force-dynamic'
をつけてSSRにしなくていいの?
(やりたいこと)
編集ページに表示される「タイトル」「本文」は常に最新のデータが必要なのでSSRにしたい。
(疑問)
export const dynamic = 'force-dynamic'
をつけてSSRにする必要はないの?💦
(結論)
編集ページのように動的なパスを含む(URLに〇〇を含む)場合は自動でSSRになるためexport const dynamic = 'force-dynamic'
をつける必要はない✨
まとめ
投稿一覧ページ
投稿一覧ページ | |
---|---|
ファイルパス | src/app/page.jsx |
URL | / |
ページの役割 |
・全投稿を表示
・投稿の削除 |
使用コンポーネント |
・PostList(投稿一覧)
・Post(単一の投稿) |
SSG/SSR/ISR | ・SSR |
Server Actions | ・投稿削除で使用 |
サーバーコンポーネント/クライアントコンポーネント | ・一部クライアントコンポーネント |
投稿作成ページ
投稿作成ページ | |
---|---|
ファイルパス | src/app/create/page.jsx |
URL | /create |
ページの役割 | ・投稿を新規作成 |
使用コンポーネント | ー |
SSG/SSR/ISR | ・SSG |
Server Actions | ・投稿作成で使用 |
サーバーコンポーネント/クライアントコンポーネント | ・サーバーコンポーネント |
投稿編集ページ
投稿編集ページ | |
---|---|
ファイルパス | src/app/edit/[id]/page.jsx |
URL | /edit/〇〇 |
ページの役割 | ・投稿を編集 |
使用コンポーネント | ー |
SSG/SSR/ISR | ・SSR |
Server Actions | ・投稿編集で使用 |
サーバーコンポーネント/クライアントコンポーネント | ・サーバーコンポーネント |
所感
- Server Actionsを使うと簡単にフォーム送信時にバックエンドの処理が呼び出せた。
-
コンポーネントを分けてサーバーコンポーネントとクライアントコンポーネントを分離することが重要。
- useStateなどはクライアントコンポーネントにする。
- Prismaのデータベース操作などはサーバーコンポーネントにする。
-
ページを作るときはSSG/SSR/ISRを意識する必要がある。
- 投稿一覧ページはSSGだと一覧データが更新されない。SSRなどにする必要がある。