Next.js 13 を試してみた
はじめに
Next.js Conf 2022でNext.js 13の発表がありました。BlogなかでNext.js13の新機能まとまっていたので引用。
- app/ Directory (beta): Easier, faster, less client JS.
- Layouts
- React Server Components
- Streaming
- Turbopack (alpha): Up to 700x faster Rust-based Webpack replacement.
- New next/image (stable): Faster with native browser lazy loading.
- New @next/font (beta): Automatic self-hosted fonts with zero layout shift.
- Improved next/link: Simplified API with automatic
<a>
.
かなり、魅力的な機能がたくさんです。
ディレクトリ構造がそのままパスルーティングされますが、Next.js 13ではReact18になり、SuspenseをつかったData FetchingやRenderingがいい感じにできるようになっているようです。
早速やってみます。
やってみた
今回は以下の2つの機能を試してみました。
今回のサンプルはこちらになります
サンプル作成
既存をマイグレーションせずに新規で作ります。
$ npx create-next-app nextjs13-sample --ts --use-npm
新規作成で、すでにNext.js 13になってるようです。
ただ、app/ Directory (beta)
はbetaなのでnext.config.jsで有効化する必要があります
/** @type {import('next').NextConfig} */ const nextConfig = { reactStrictMode: true, swcMinify: true, experimental: { appDir: true, }, } module.exports = nextConfig
appディレクトリに移す
新規作成時は従来通りの./pages
でルーティングが設定されてるので、appを有効化しても、pagesが存在するとエラーになってしまいます。ばっさり削除します。
appディレクトリを作成します。
$ rm -rf pages $ mkdir app
いままでpagesには基本にはpageファイルだけで、アプリで共通の設定が_documentや_appなどでしたが、それが各ページ毎におけるようになったイメージです。
- page.tsx: ページで読みこまれる(いままでpagesにおいていたファイル相当)
- layout.tsx: ページ毎のレイアウト。
- loading.tsx: Suspenseが発生した時のローディングView
- error.tsx: Suspenseでエラーが発生したきのエラーView
- template.tsx: レイアウトにてるけどちょっと違う。レイアウトは状態を維持するけどテンプレートは常に新しいインスタンスされ状態の引き継がない。
- head.tsx:
Head
の設定
いままではindex.jsを読み込まれるようになってましたが、page.jsを読み込まれるようになります。
サンプルとしてGitHubのUsersを表示するページを作ります。
layoutを作成
基礎的なHtmlの雛形のlayoutで作成。
import { FC, PropsWithChildren } from "react"; const RootLayout: FC<PropsWithChildren> = ({ children }) => { return ( <html lang="en"> <head> <title>Next.js</title> </head> <body>{children}</body> </html> ); }; export default RootLayout;
loadingを作成
GitHub Users APIをfetchでSuspenseで読み込み、そのときのローディングViewを作成
export default function Loading() { return <div>Loading...</div>; }
pageを作成
Reactのuseを使ってデータを表示します。(あれもうuseつかえるのか。。。)
import { use } from "react"; type User = { id: number; login: string; }; const fetchUsers: () => Promise<User[]> = async () => { const res = await fetch("https://api.github.com/users"); return res.json(); }; export default function Page() { const users = use(fetchUsers()); return ( <div> <h1>GitHub Users!</h1> <div> {users.map((user) => { return ( <div key={user.id}> {user.id}: {user.login} </div> ); })} </div> </div> ); }
実際に動かす
$ npm run dev
まとめ
React18のSuspenseがやはり起爆剤で、色々追加/変更がありますが、かなり嬉しい変化だと思っています。
Rustの影響でまた新たなビルドツールTurbopackもでてきましたし、変化が激しい時期がまだまだ続きそうですね。