Next.js Appフォルダでの変更点を20個、時短で紹介
2023.12.122024.10.30
この記事は約3分で読めます
目次
この記事の筆者:三好アキ
🔹 専門用語なしでプログラミングを教えるメソッドに定評があり、1200人以上のビギナーを、最新のフロントエンド開発入門に成功させる。
🔹 Amazonベストセラー1位を複数回獲得している『はじめてつくるReactアプリ with TypeScript』著者。
Amazon著者ページはこちら → amazon.co.jp/stores/author/B099Z51QF2
React、Next.js、TypeScriptなどのお役立ち情報や実践的コンテンツを、ビギナー向けにかみ砕いて無料配信中。登録はこちらから → 無料メルマガ登録
お知らせ:新刊書リリース
2024年11月に、Server Actionsを使ってフルスタックアプリを開発する新刊書をリリースしました。
Next.js/Reactビギナー向け入門です。
2024年11月時点で最新のNext.jsバージョン15を使用しています。
Next.js Server Actionsでつくるフルスタックアプリ
【2024年11月リリース。少ないコードですばやく本格的なフルスタックアプリを開発する方法を紹介】
880円 → 0円
1 フォルダ構成(フロントエンド)
Appフォルダではフォルダ名がURLとして使われ、コードはその中に作ったpage.jsに書きます。
動的ページ(ブログの記事ページやアイテムページなど)では、[id]
や[slug]
のように[ ]
を使った名前をフォルダ名として使います。
URL | 従来(Pagesフォルダ) | v13以降(Appフォルダ) |
---|---|---|
/ | /pages/index.js | /app/page.js |
/blog | /pages/blog.js | /app/blog/page.js |
/blog/2024-12-1-cafe-book | /pages/blog/[id].js | /app/blog/[id]/page.js |
2 フォルダ構成(バックエンド)
API/バックエンド開発を行う場合も、フォルダの名前がURLに使われるという規則は同じです。
従来(Next.jsバージョン12以前)はapi
というフォルダを作るのがマストでしたが、Appフォルダではapi
フォルダ作成が必須ではありません。route.js
という名前のファイルを作れば、それがRoute Handlersとして機能します。
URL | 従来(Pagesフォルダ) | v13以降(Appフォルダ) |
---|---|---|
/api/item/create | /pages/api/item/create.js | /app/api/item/create/route.js |
/api/article/2024-12-1-cafe-book | /pages/api/article/[id].js | /app/api/article/[id]/route.js |
/api/blog/readsingle/20240914-studying-english | /pages/api/blog/readsingle/[id].js | /app/api/blog/readsingle/[id]/route.js |
3 サーバーコンポーネントとクライアントコンポーネントの比較
Appフォルダ内ではReactサーバーコンポーネントがデフォルトです。
目的 | サーバーコンポーネント | クライアントコンポーネント |
---|---|---|
データを取得する | ○ | × |
バックエンドのリソースに直接アクセスする | ○ | × |
onClickなどのユーザー操作機能 | × | ○ |
useStateやuseEffectの使用 | × | ○ |
4 従来のReactを使う方法(use client)
デフォルトのReactサーバーコンポーネントでuseState
やuseEffect
などを使いたい場合には、ファイル冒頭に"use client"
と書き、従来のReactコンポーネント(クライアントコンポーネント)へと変更します。
"use client"
import { useState } from "react"
const Hello = () => {
const [data, setData] = useState()
return (
<div>
...
5 URLパスの取得(フロントエンド)
next/navigation
を使って次のように書きます。
import { usePathname } from "next/navigation"
const Hello = () => {
const pathname = usePathname()
console.log(pathname) // /blog/first-article
return(
<div>
...
従来(Next.jsバージョン12以前)は次のように書いていました。
import { useRouter } from "next/router"
const Hello = () => {
const router = useRouter()
console.log(router.asPath) // /blog/first-article
return(
<div>
...
6 リダイレクト(フロントエンド)
next/navigation
を使って次のように書きます。
import { useRouter } from "next/navigation"
const Hello = () => {
const router = useRouter()
router.push("/success")
OR
router.replace("/success")
return(
<div>
...
従来(Next.jsバージョン12以前)は次のように書いていました。
import { useRouter } from "next/router"
const Hello = () => {
const router = useRouter()
router.push("/success")
OR
router.replace("/success")
return(
<div>
...
7 APIルートの作り方(GETリクエスト)
Appフォルダ内でAPI開発をするときのコードも大きく変わっています。下記はGETリクエストを行う最もベーシックなコードです。
// app/api/hello/route.js
import { NextResponse } from "next/server"
export async function GET() {
return NextResponse.json("ハロー")
}
従来(Next.jsバージョン12以前)は次のように書いていました。
// pages/api/hello.js
export default function hello(req, res){
return res.json("ハロー")
}
Next.jsでつくるフルスタックアプリ
【最新バージョンのNext.jsとAppフォルダで、フルスタックアプリを自力で作る力を手にいれる】
1980円 → 0円
8 APIルートのPOSTとPUTとDELETEメソッド
HTTPメソッドの変更は、GET
やPOST
やDELETE
を明示して行います。
export async function POST() {
return NextResponse.json("ハロー")
}
export async function DELETE() {
return NextResponse.json("ハロー")
}
9 リクエストBodyの解析方法
Appフォルダではrequest.json()
を使います。
import { NextResponse } from "next/server"
export async function POST(request) {
const reqBody = await request.json()
console.log(reqBody) // リクエストbodyの中身が表示
return NextResponse.json("ハロー")
}
従来(Next.jsバージョン12以前)は次のように書いていました。
export default function hello(req, res){
console.log(req.body) // リクエストbodyの中身が表示
return res.json("ハロー")
}
10 バックエンドでのパラメータ取得(context)
バックエンド側でURLのパラメータを取得したい場合、context.params.id
を使って次のようにします。
なおcontext
はカッコ内の2つ目の値として書く必要があるので、ここではrequest
も書いています。
import { NextResponse } from "next/server"
export async function GET(request, context) {
console.log(context.params.id)
return NextResponse.json("ハロー")
}
従来(Next.jsバージョン12以前)はreq.query.id
で取得をしていました。
const getSingleItem = async(req, res) => {
console.log(req.query.id)
return res.json("ハロー")
}
export default getSingleItem
11 _app.jsの廃止とlayout.jsの導入
従来(Next.jsバージョン12以前)、すべてのページで適用したいスタイルや設定などは_app.js
で行っていましたが、Appフォルダではlayout.js
がその代わりを果たします。
layout.js
という名前のファイルを作ると、そのフォルダ配下のすべてのファイルに適用されます。
(下記例ではblog
フォルダ内にlayout.js
を作ると、配下にあるsummer
、winter
にも適用されます。)
12 getStaticPathsの廃止とgenerateStaticParamsの導入
動的ページのURL生成・登録のために使われていたgetStaticPaths
は、generateStaticParams
に変更されました。
const SingleBlog = () => {
return (
<h1>SingleBlogページ</h1>
)
}
export default SingleBlog
export async function generateStaticParams() {
// マークダウンファイルや外部データベースなどからURL名/ファイル名を取得するコード
return paths
}
従来(getStaticPaths
)は次のように書いていました。
const SingleBlog = () => {
return (
<h1>SingleBlogページ</h1>
)
}
export default SingleBlog
export async function getStaticPaths() {
// マークダウンファイルや外部データベースなどからURL名/ファイル名を取得するコード
return {
paths: paths,
}
}
13 getStaticPropsの廃止
スタティック・サイトの動的ページのデータ取得時に使われていたgetStaticProps
や、サーバーサイドレンダリング時のデータ取得に使われていたgetServerSideProps
は廃止され、データベースへの直接アクセスや、JavaScriptのfetch()
でデータ取得を行えるようになりました。
(*このfetch()
はNext.jsによって高機能化されており、キャッシュの設定なども行えます)
const getSingleItem = async(id) => {
const response = await fetch("http://localhost:3000/api/item/readsingle/${id}")
const jsonData = await response.json()
const singleItem = jsonData.singleItem
return singleItem
}
const ReadSingleItem = async(context) => {
const singleItem = await getSingleItem(context.params.id)
return (
<div>
....
14 プロジェクト全体に適用したい機能(middleware.js)
middleware.js
という名前のファイルを作ると、ユーザーからのアクセスはすべてこのmiddleware.js
を通過します。アクセス認証やリダイレクト処理のコードを書くときに便利です。
ポイントはapp
フォルダと同じ階層に作ること、そして名前を必ずmiddleware.js
にすることです。
15 middleware.jsの適用範囲を制限する
middleware.js
はデフォルトでは、全ルートに対するすべてのリクエストが通過する設定になっています。
もしmiddleware.js
の働きを特定のルートだけに制限したい場合は、matcher
を使いましょう。
(*フォルダ配下すべてに適用したい場合は:path*
と書きます)
// middleware.js
import { NextResponse } from "next/server"
export async function middleware() {
return NextResponse.next()
}
export const config = {
matcher: ["/about", "/api/item/create", "/api/item/update/:path*"],
}
16 メタデータの設定方法
ページタイトルやdescription
などのメタデータは、従来(Next.jsバージョン12以前)は<Head>
を使っていましたが、Appフォルダでは次のように設定します。
// app/page.js
export const metadata = {
title: "トップページ",
description: "弊社はAI分野のリーディングカンパニーです。",
}
const Index = () => {
return (
<div>
...
データによって表示内容の変わる動的ページの場合は、generateMetadata
を使い、データ取得のコードを書く必要があります。
// app/blog/[id]/page.js
export async function generateMetadata() {
// マークダウンファイルや外部データベースなどからデータを取得するコード
return {
title: data.title,
description: data.excerpt,
}
}
const SingleBlog = async() => {
return (
<div>
...
しかし実はもっと簡単に設定する方法もあり、それはクライアント・コンポーネントにも使える方法です。下記記事を参考にしてください。
17 ローディングの設定方法
APIなどからデータを取得するファイルと同じフォルダ内にloading.js
という名前のファイルを作ると、データ取得中にはそれが表示されます。
18 404ページの設定方法
not-found.js
をapp
フォルダ内に作ると、404ページとして機能します。
次のように表示されます。
19 next/imageをheightとwidthの設定なしで使う
next/image
ではheight
とwidth
の設定がマストですが、import
で読み込んだ画像の場合は、それらの設定は不要になります。
import Image from "next/image"
import profilePic from "./myself.png"
const Hello = () => {
return (
<Image src={profilePic} />
)
}
Next.jsでつくるフルスタックアプリ
【最新バージョンのNext.jsとAppフォルダで、フルスタックアプリを自力で作る力を手にいれる】
1980円 → 0円
20 環境変数の使い方
.env.local
ファイル内で設定した環境変数は、process.env.変数名
で呼び出せます。
// .env.local
URL = https://nextjsbook-fullstack-app-folder.vercel.app
呼び出し。
fetch(`${process.env.URL}/api/item/readall`)
しかしこれはサーバーサイドのコードでしか呼び出せないため、クライアント(ブラウザ)サイドのファイルから呼び出したい場合はNEXT_PUBLIC_
をつけます。
// .env.local
NEXT_PUBLIC_URL = https://nextjsbook-fullstack-app-folder.vercel.app
呼び出し。
fetch(`${process.env.NEXT_PUBLIC_URL}/api/item/readall`)
21 開発環境と本番環境(Vercel)のURLを自動で切り替える
手元のコンピューターでの開発時にバックエンドのURLとしてhttp://localhost:3000
を使っている場合、デプロイのたび、URLをVercelが割り当てている公開URLに変更する必要があり、手間がかかります。
開発環境でのURLは.env.development
に、本番環境でのURLは.env.production
に次のように設定し、プロジェクト内のURLをすべてprocess.env.変数名
に置き換えると、手元のコンピューターでは.env.development
のURLが、デプロイ時には.env.production
のURLを、Vercelが自動で切り替えてくれます。
// .env.development
NEXT_PUBLIC_URL=http://localhost:3000
// .env.production
NEXT_PUBLIC_URL=https://nextjsbook-fullstack-app-folder.vercel.app
22 フォントの設定方法
最適化されたGoogle fontがnext/font
で簡単に使えます。
フォント設定は、サイトやアプリ全体に適用するのが普通なので、多くの場合layout.js
に書きます。
// app/layout.js
import { Eczar } from "next/font/google"
// ⬆フォントを読み込み
const font = Eczar({ subsets: ["latin"] })
// ⬆フォントの設定
export default function RootLayout({ children }) {
return (
<html>
// ⬇フォントを適用
<body className={font.className}>
{children}
</body>
</html>
)
}
以下、ビギナーの方がよく挙げる不明点を2つ解説します。
フォント名について
2文字以上のフォント名、たとえば「Shantell Sans」や「 Advent Pro」のようなフォントは、間にアンダースコアを挟んで次のように書きます。
import { Shantell_Sans } from "next/font/google"
const font = Shantell_Sans({ subsets: ["latin"] })
...
import { Advent_Pro } from "next/font/google"
const font = Advent_Pro({ subsets: ["latin"] })
...
subsetsについて
「subsets」とは必要な文字だけを抜き出すことです。
文字には「A、B、C、a、b、c....」といったアルファベットの文字だけでなく、キリル文字やギリシャ文字、ハングル、ひらがな、カタカナ、漢字といった表記法もあります。
フォントによっては、アルファベットだけでなくギリシャ文字なども含まれているものがあり、その場合ギリシャ文字の読み込みの分だけ負荷が上がるので、「subsets」でアルファベットの読み込みだけを指定しましょう。
アルファベットだけを読み込むときには、上記例のようにsubsets: ["latin"]
と書きます。
*フォントによっては、次のようにweight
の設定がマストの場合もありますが、その場合はエラーが表示されるので、それに従って修正しましょう。
import { Klee_One } from "next/font/google"
const font = Klee_One({
subsets: ["latin"],
weight: "400",
})
...
23 フォルダ名をURLに反映させない方法
app
フォルダ内では、フォルダの名前がURLに反映されます
たとえば次のように、マーケティング(marketing
)とセールス(sales
)フォルダを作成し、その中にabout
とprofit
フォルダを作ったとします。
URLは次のようになります。
app/marketing/about/page.js
→ /marketing/about
app/sales/profit/page.js
→ /sales/profit
しかし、グループ分けや整理整頓のためにフォルダを作りたい場合もあります。つまりURLに反映されないフォルダを作りたいときです。
その場合は、下図のように丸カッコでフォルダ名をはさみましょう。
このようにすると、フォルダ名がURLに反映されなくなり、URLは次のようになります。
app/(marketing)/about/page.js
→ /about
app/(sales)/profit/page.js
→ /profit
Next.jsでつくるフルスタックアプリ
【最新バージョンのNext.jsとAppフォルダで、フルスタックアプリを自力で作る力を手にいれる】
1980円 → 0円
24 Server ActionsとAPI、どっちを使う?
Server Actionsを使えば、API(Route Handler)を作らなくてもダイレクトにデータベースとの連携やCRUD操作が可能ですが、それぞれに強み/弱みがあります。
API(Route Handlers) | Server Actions | |
---|---|---|
特徴 | 汎用的 | 限定的 |
用途 | データベースとの複雑な連携操作があるケース | シンプルなCRUD操作が主のケース |
メリット | APIを、他のアプリケーションやモバイルアプリも利用可 | コードの記述量を抑え、コンパクトかつ短時間で開発可 |
デメリット | コードの記述量や開発工程が増える | そのNext.js/Reactアプリでしか利用できない |
くわしくは下記記事も参考にしてください。
25 Next.jsをVercel以外でデプロイする方法
手元のコンピューターで、あらかじめexportとbuildを行う必要があります。exportのコードをnext.config.mjs
に追加しましょう。
// next.config.mjs
/** @type {import('next').NextConfig} */
const nextConfig = {
output: "export", // 追加
};
export default nextConfig;
そしてnpm run build
コマンドを実行するとout
フォルダができるので、それをデプロイします。
なおデプロイ後、画像が表示されない問題などが発生する場合は、下記記事を参考にしてください。
26 build時に特定のURLを除外する方法
特定のURLをbuild時に除外する方法で一番簡単なのは、該当のフォルダ(or ファイル)自体をapp
フォルダやpages
フォルダから取り除く方法です。
しかしnext.config.mjs
にコードを書いて行う方法もあるので、くわしくは下記記事を参考にしてください。
メルマガ配信中
(from 三好アキ/エンジニア)
React、Next.js、TypeScriptなど最新のウェブ開発のお役立ち情報を、ビギナー向けにかみ砕いて無料配信中。
(*配信はいつでも停止できます)