Next.jsバージョン13の変更点を時短で解説
2023.04.19
2023.05.18
この記事は約3分で読めます

この記事の筆者:三好アキ
🟢 専門用語なしでプログラミングを教えるメソッドに定評があり、1200人以上のビギナーを、最新のフロントエンド開発入門に成功させる。
🟢『はじめてつくるReactアプリ with TypeScript』、『動かして学ぶ!Next.js/React開発入門(翔泳社/*韓国でも出版)』著者。
▼ Amazon著者ページはこちら
amazon.co.jp/stores/author/B099Z51QF2
Next.js v13のAppフォルダ
Next.jsバージョン13ではAppフォルダが導入され、これによってルーティングやデータ取得の方法が大きく変わりました。
本記事ではその変更点をコードを見ながら紹介します。
よりくわしくAppフォルダを使った最新のNext.jsについて知りたい方は、先日リリースした下記書籍を参考にしてください。
はじめてつくるNext.jsサイト
【最新バージョンのNext.jsとAppフォルダで、時短でNext.jsを習得。作りながら学ぶ実践形式】
1848円 → 0円
なお本記事では全般的な「大きな」変更点について紹介しています。パス取得やリダイレクトのコード、apiフォルダといった個別的な「小さな」変更点は次の記事を参考にしてください。
v13のインストール
最新版のNext.jsのインストールから始めましょう。ターミナルを開いて任意のフォルダへ移動し、次のコマンドでNext.jsをインストールしてください。
npx create-next-app@latest nextjs13-app-test最後の@latestによって、その時点での最新版がインストールされます。フォルダ名はここではnextjs13-app-testとしています。
インストール開始前に次のような質問が出ます(2023年5月現在)。
? Would you like to use TypeScript with this project? … No / Yes
? Would you like to use ESLint with this project? … No / Yes
? Would you like to use Tailwind CSS with this project? … No / Yes
? Would you like to use `src/` directory with this project? … No / Yes
? Use App Router (recommended)? › No / Yes
? Would you like to customize the default import alias? › No / Yes「Yes」か「No」を矢印キーで選択して「Enter」で決定します。TypeScript、ESLint、Tailwind CSS、src directory利用の質問には「No」を選択してください。そして「Use App Router (recommended)」の質問には「Yes」を選ぶことで、v13の新機能appフォルダが利用できるようになります。最後の「customize the default import alias」は今回重要ではないので「No」を押して進んでください。
インストールが完了したらVSコードで開きましょう。package.jsonを見ると、"next": "13.x.x"とあり、Next.jsのversion 13がインストールされているのがわかります(執筆時点では"next": "13.3.0")。
appフォルダ
v13ではフォルダ構成の方法に根本的な変更が加えられました。なお現時点(2023年4月)ではこの機能はまだ「experimental(実験段階)」ですが、今後はこれがデフォルトになっていくと考えられます。
(*5月4日にリリースされたNext.js v13.4よりstable(安定版)となりました)
まずnext.config.jsを見てください。
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
appDir: true,
},
}
module.exports = nextConfigexperimentalという文字が見え、appDirつまり「app Directory(appフォルダ)」機能が追加されているのがわかります。
次にフォルダ構成を見ると、最初に気がつくのはappフォルダのあることです。
従来まではpagesフォルダ内にabout.js、contact.jsといったような各ページを作ってきましたが、appフォルダでは各ページ毎にひとつフォルダを作り、その中にpage.jsというファイルを作る構成となります。
表にすると以下のようになりますが、実際に試した方がわかりやすいのでコードを見ながら解説していきます。
| URL | 従来 | v13 |
|---|---|---|
| / | /pages/index.js | /app/page.js |
| /about | /pages/about.js | /app/about/page.js |
| /contact | /pages/contact.js | /app/contact/page.js |
まずapp/page.jsを見てください。これは従来のpages/index.jsにあたります。
最初に/aboutページを作ってみましょう。appフォルダ内にaboutというフォルダを作ります。
この中にファイルpage.js作ります。
そこに次のコードを打ってください。普通のReactのコードです。
// app/about/page.js
const About = () => {
return (
<h1>Aboutページ</h1>
)
}
export default About保存し、Next.jsを次のコマンドで起動しましょう。
npm run devhttp://localhost:3000/aboutにアクセスするとAboutページが開きます(CSSスタイルとしてglobals.cssが当たっています)。
同じ要領でコンタクトページを作ってみましょう。まずcontactフォルダをappフォルダ内に作ります。
その中にpage.jsファイルを作りましょう。
次のコードを打ちます。
// app/contact/page.js
const Contact = () => {
return (
<h1>Contactページ</h1>
)
}
export default Contact保存して、http://localhost:3000/contactにアクセスするとContactページができているのがわかります。
ここまでで、従来のようにファイル名ではなく、フォルダ名がページのURLと対応しているのがわかりました。
従来のNext.jsの動的ページで使った特殊な名前を持つファイル、[slug].jsの作り方も発想としては同じです。[slug]という名前をファイルではなくフォルダに使います。実際に確認してみましょう。
まずblogフォルダを作り、その中にpage.jsを作ります。
そこに次のコードを打てば/blogページができます。
// app/blog/page.js
const Blog = () => {
return (
<h1>Blogページ</h1>
)
}
export default Blogblogフォルダの中に[slug]フォルダを作ってください。
その中にpage.jsファイルを作ります。
そこに次のコードを打ちます。
// app/blog/[slug]/page.js
const SingleBlog = () => {
return (
<h1>SingleBlogページ</h1>
)
}
export default SingleBlog保存します。URL欄のhttp://localhost:3001/blog/の/blog/以下にどの文字列をつなげても、いま作ったページが表示されるようになります。たとえばhttp://localhost:3001/blog/aabbccやhttp://localhost:3001/blog/xxyyzzなどです。
なおこのページでURLのパラメータを取得するには次のようにします。
// app/blog/[slug]/page.js
const SingleBlog = (props) => { // 追加
console.log(props.params.slug) // 追加
return (
<h1>SingleBlogページ</h1>
)
}
export default SingleBlogpropsに含まれたparams内部のslugで、URLのパラメーターを取得できます。なおここでslugとなっているのはフォルダ名が[slug]であるからで、もしフォルダ名が[id]や[abc]の場合、それぞれprops.params.id、props.params.abcとなります。
Layoutコンポーネント
従来までサイト全体に適用したいスタイルなどは_app.jsに書き加えていましたが、v13ではappフォルダ内にlayout.jsというファイルを作ると、それがサイト全体に適用されます。
現在appフォルダを見ると、すでにlayout.jsがあり、これがサイト全体で適用されています。本当に適用されているのか確認したいので、次のように余分なタグを書き加えてみましょう。
// app/layout.js
import './globals.css'
export const metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
}
export default function RootLayout({ children }) {
return (
<html lang="en">
<body><h1>テスト</h1>{children}</body> // 追加
</html>
)
}保存して/about、/contactなどにアクセスすると、「テスト」という文字が表示され、たしかにlayout.jsファイルが全ページに適用されているのがわかります。
しかし一部のページでは別のレイアウトを適用したいというケースもあります。その場合はどうすればいいのでしょうか。
実はページ毎に作ったフォルダの中にlayout.jsを作ると、それがフォルダ内のすべてのページに適用されます。試してみましょう。
blogフォルダ内にlayout.jsを作ります。
次のコードを打ちます。
// app/blog/layout.js
export default function BlogLayout({ children }) {
return (
<body>
<div>
<h1>ブログページレイアウト</h1>{children}
</div>
</body>
)
}保存してhttp://localhost:3000/blogを開くと、app/layout.jsのレイアウトではなく、いま作ったapp/blog/layout.jsが適用されているのがわかります
http://localhost:3000/blog/xyzを開いてもそれが適用されているので、/blog/以下のページにはすべてblogフォルダ内のlayout.jsが適用されているのがわかります。
getStaticPathsとgetStaticPropsの変更点
appフォルダにはReact Server Componentsという仕組みが使われているため、appフォルダ内ではgetStaticPathsとgetStaticPropsが使えなくなりました。appフォルダ内で動的データをあつかう新しいコードの書き方の例を紹介します。
まず準備として、ダミーデータの入ったdataフォルダとそのデータ取得のためのutilsフォルダを拙著『はじめてつくるNext.jsサイト』の下記完成見本コードよりダウンロードし、appフォルダ内に配置してください。
完成見本コード: https://github.com/mod728/nextjs-book-portfolio-site
次にマークダウンファイルを扱うためのパッケージをインストールしましょう。
npm install raw-loader gray-matterそしてnext.config.jsにraw-loaderを使うコードを書き加えます。
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
appDir: true,
},
// ⬇追加
webpack: function (config) {
config.module.rules.push({
test: /\.md$/,
use: "raw-loader",
})
return config
},
// ⬆追加
}
module.exports = nextConfig以上で準備が完了です。
URLの生成・登録に使われるgetStaticPathsの新しいバージョンとして導入されたのがgenerateStaticParamsです。次のように書きます。
// app/blog/[slug]/page.js
import { getAllBlogs } from "../../utils/mdQueries"
const SingleBlog = () => {
return (
<h1>SingleBlogページ</h1>
)
}
export default SingleBlog
export async function generateStaticParams() {
const { orderedBlogs } = await getAllBlogs()
const paths = orderedBlogs.map((orderedBlog) => `/${orderedBlog.slug}`)
return paths
}getStaticPathsとともに、ページで表示するデータ取得のために使っていたのがgetStaticPropsでした。
appフォルダ内ではgetStaticPropsは廃止され、データに直接アクセスする方法(下記例)や、JavaScriptのfetch()でデータ取得ができるようになっています。コード例として次のようになります。なお非同期処理のasyncを書き忘れないようにしましょう。
// app/blog/[slug]/page.js
import { getAllBlogs, getSingleBlog } from "../../utils/mdQueries"
const SingleBlog = async(props) => {
const { singleDocument } = await getSingleBlog(props)
console.log(singleDocument)
return (
<h1>SingleBlogページ</h1>
)
}
export default SingleBlog
export async function generateStaticParams() {
const { orderedBlogs } = await getAllBlogs()
const paths = orderedBlogs.map((orderedBlog) => `/${orderedBlog.slug}`)
return paths
}さらにくわしく知りたい方はビギナー向けの下記書籍を参考にしてください。
2時間程度でストレスなく、かつ挫折することなく終えられるビギナーに優しい内容になっています。

🟩 フロントエンド開発者入門ガイド【無料配布中】
最初にこれが知りたかった!
フロントエンド初心者が必ず押さえておきたい ― 『挫折しない勉強法』とその具体的ステップ、無料配布中。
(*名前不要・メールアドレスだけで受け取り可能です)


