Next13の大事そうなところをまとめてみた
開発環境
- next 13.0.6
前提
2022年12月時点の公式ドキュメント(Next 13 app directory (beta) docs を主に参考にしています。
本題
Special Files
これまでは共通設定を_document.tsxや_app.tsxで定義していましたが、ページごとにローディングやエラー、ヘッドなどを配置できるようになりました。
<Layout>
<Template>
<ErrorBounday fallback={<Error />}>
<Suspense fallback={<Loading />}>
<Page />
</Suspense>
</ErrorBounday>
</Template>
</Layout>
-─ app
├── layout.tsx
├── template.tsx
├── error.tsx
├── loading.tsx
└── page.tsx
【注意点】
- appディレクトリ直下に配置する場合、ルートファイルとなり共通設定にすることができます。
- ルートに配置するlayoutは必ずhtml、bodyタグを配置する必要があります。
- appディレクトリの中ではデフォルトでサーバーコンポーネントになる
- ファイルを配置すると自動的にPageコンポーネントをラップする
- サーバーコンポーネントで発生したエラーはクライアント側で表示させる必要があるので、error.tsxは’use client’を宣言してクライアントコンポーネントにする
Web fetch() API
fetchAPIを利用してデータフェッチを行う際、キャッシュオプションを設定することでSSG, SSR, ISRを使い分けるようになりました。
何も指定しなければデフォルトでSSGとなります。
# SSG (デフォルト)
fetch(URL, { cache: 'force-cache' })
# SSR
fetch(URL, { cache: 'no-store' })
# ISR
fetch(URL, { next: { revalidate: 10} })
When to use Server vs. Client Components?
サーバーコンポーネントの特徴
- サーバーでレンダリングされる(クライアントにjsは送られない)
- データフェッチにasync functionを使用できる
- Secure keyを使用可能
- ブラウザAPIは使用不可
- hooks(useState, useEffectなど)は利用不可
- Event Listner(onClickなど)は利用不可
クライアントコンポーネントの特徴
- ブラウザでjsが実行される
- データフェッチはuseEffect, react-query, SWR, useなど利用する
- Secure keyを使用不可
- hooks(useState, useEffectなど)を使用可能
- Event Listner(onClickなど)を使用可能
どう使い分ける?
公式には・・
とあるので、基本的にはクライアントでしかできないこと以外はサーバーでやるのが推奨のようです。
Mutating Data
サーバーコンポーネントでのデータ再取得についてはrouter.refresh()が推奨されています。
こちらはクライアント側(React)の状態を保持しつつ宣言的にデータ取得を行うもので、イベントハンドラーなど何かしらのトリガーでインタラクティブに更新できるようになりました。
Nested Layout
セグメントをネストしていく際、各階層でlayout.tsxを作成すると累積していきます。
Streaming and Suspense
SSRでデータフェッチをする際、プリレンダリングが完了するまではクライアント側で何も表示できません。
なるべく早くコンテンツを表示させなければUXの悪いアプリケーションになってしまいます。
また、データフェッチを行うサーバーコンポーネントのレンダリングができないことが、他の本来はすぐに表示できるコンテンツ(コンポーネント)の表示までも遅らせてしまいます。
そこで、サーバーコンポーネントとSuspenseを組み合わせることで表示に時間のかかるサーバーコンポーネントのみを(例えば)ローディング状態にして、他のコンテンツを表示させることができます。
import { Suspense } from 'react';
import { UsersList, ArticlesList } from '../components';
const SamplePage = () => (
<>
<Suspense fallback={<div>Loading..</div>}>
<UsersList />
</Suspense>
<Suspense fallback={<div>Loading..</div>}>
<ArticlesList />
</Suspense>
</>
);
export default SamplePage;
上記の例ではUsersListが件数が多く、レンダリングコストの高いコンポーネントだと仮定し、ArticlesListはすぐに表示できるコンポーネントと仮定します。
この場合、UsersListのプリレンダリングが完了することを待たずして、ArticlesListはすぐに表示され、インタラクティブに操作可能になります。
さいごに
React18の記事でも述べましたが、さいごにご紹介したStreaming and Suspenseなど並行処理をうまく活用してUXを高めていくことが今後のフロントエンド開発のテーマの1つになるのかなと思うので、サーバーコンポーネントをまずはしっかり理解していきたいです!