Next.js Segmentを構成するファイルの使い方

# はじめに
この記事では page.tsx, layout.tsx 以外のSegment構成ファイルに関する情報を発信します。

# 目次
<!-- タイトルとアンカー名を編集 -->
1. [loading.tsx](#Chapter1)
1. [not-found.tsx](#Chapter2)
1. [error.tsx](#Chapter3)
1. [global-error.tsx](#Chapter4)
1. [route.tsx](#Chapter5)
1. [default.tsx](#Chapter6)
1. [参考文献](#reference)

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# loading.tsx
データ取得がある画面ではローディングを使用するかと思います
ここではその有効方法と確認方法を記載します。
※ストリーミングは本記事では扱いません

### ローディングファイルの有効化と確認
```
app/
 └─ sample/
    ├─ loading.tsx
    └─ page.tsx
```
```tsx:loading.tsx
export default function Loading(){
	return <>...loading</>;
}
```
通常はローディングスピナーやスケルトンでUIを記述すると思いますが、今回はこれで十分です :bird:
使用したいツリー内に上記ファイルを設置すれば OK !!
```tsx:page.tsx
export default async function Page() {
  await new Promise(resolve => setTimeout(() => resolve(""), 2000));
  return (
      <div>sample</div>
  )
}
```
ローディングの発火を検証するための処理を加えたら、ブラウザで確認してみてください !
2秒ほど「...loading」が表示されるはずです

#### Good to know
* loading.tsxへpropsは渡せない

<a id="#Chapter2"></a>
# not-found.tsx
404エラーをキャッチし、404UIを提供するファイルです
ここではその有効方法と確認方法を記載します。

### 404画面の有効化と確認
```
app/
 └─ sample/
    ├─ not-found.tsx
    └─ page.tsx
```
```tsx:not-found.tsx
export default function NotFound() {
    return (
      <div>
        <h1>ページが見つかりません</h1>
        <p>お探しのページは存在しないか、削除された可能性があります。</p>
        <a href="/">ホームに戻る</a>
      </div>
    );
}
```
```tsx:page.tsx
import { notFound } from "next/navigation";

export default function Page() {
    notFound();
    return (
        <div>sample not found</div>
    )
}
```
ブラウザで該当画面を表示すると、not-found.tsxのUIが確認できると思います :bird:
not-found.tsxを app/ に配置するとグローバルなファイルとなり、アプリ全体の404エラーをキャッチ出来るようになります。
ツリー毎に置いてもいいですが、404のUIを細かく変更する必要に迫られることは中々ないと思いますので、通常は app/ に1つ配置するのがスタンダードな配置かと思います
#### Good to know
* not-found.tsxへpropsは渡せない

<a id="#Chapter3"></a>
# error.tsx
データ取得や画面の提供の際に例外が発生した場合、エラーを通達するUIを提供するファイルです
ここではその有効方法と確認方法を記載します。

### エラー画面の有効化と確認
```
app/
 ├─ error.tsx
 └─ page.tsx
```
```tsx:error.tsx
'use client'
 
export default function Error({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  return (
    <div>
      <h2>Something went wrong!</h2>
      <button onClick={() => reset()}>Try again</button>
    </div>
  )
}
```
```tsx:page.tsx
export default function Page() {
  throw new Error("This is a test error!");
}
```
ブラウザで該当画面を表示すると、error.tsxのUIが確認できると思います :bird:
下記画像(公式)からも分かるようにerror.tsxは、配置した時点でErrorBoundaryのfallbackに自動的に充てられる仕組みになっています。
また、ErrorBoundaryはLayoutの内側でネストされていますので、同階層のlayout.tsxで発生したエラーはキャッチできません。最も近い親ErrorBoundaryまでバブルアップします
![スクリーンショット 2024-10-13 1.37.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/606316/5f54ea04-4441-add0-6343-a6362ed6dd15.png)

#### Good to know
* クライアントコンポーネントで定義する必要があります
* RootLayout 内で発生したエラーのキャッチは global-error.tsxの役割となります

<a id="#Chapter4"></a>
# global-error.tsx
error.tsx同様にデータ取得や画面の提供の際に例外が発生した場合、エラーを通達するUIを提供するファイルです
global-error.js は運用環境でのみ有効となるファイルなので私自身検証できていませんが、おそらくこれで有効になるだろうというコードを記載します

### エラー画面の有効化と確認
```
app/
 ├─ global-error.tsx
 └─ layout.tsx
```
```tsx:global-error.tsx
"use client";

export default function GlobalError({
  reset,
}: {
  error: Error & { digest?: string };
  reset: () => void;
}) {
  return (
    <html>
      <body>
        <h2>Something went wrong!</h2>
        <button onClick={() => reset()}>Try again</button>
      </body>
    </html>
  );
}
```
```tsx:layout.tsx
export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  const throwError = () => {
    throw new Error("This is a test error!");
  };
  throwError();
  
  return (
    <html lang="en">
      <body className={inter.variable}>
          {children}
      </body>
    </html>
  )
}
```
開発環境等でブラウザを開くと、「This is a test error!」が表示されます。
RootLayoutで発生したエラーはerror.tsxでキャッチできないので、global-error.tsxが活躍してくれるはずです:sweat_smile:


#### Good to know
* クライアントコンポーネントで定義する
* Segment単位で設置しないファイル
* このUIが表示されるときはRootLayoutと置き換えられるので、html・bodyタグを記載

<a id="#Chapter5"></a>
# route.tsx
Web APIを提供するためのファイルです
App Routerで実装するWeb APIを Route Handlerと呼び、基本的には /app/api/ 配下に配置します
ここではその有効方法と確認方法を記載します。

### Route Handlerの有効化と確認
```
.env
app/
 └─ api
    └─ sample
       └─ route.tsx
 └─ sample
    └─ page.tsx
```
```tsx:route.tsx
import { NextResponse } from "next/server";

export async function GET(req: Request){
    const hello = [
        { "name": "北海道・東北", "value": "1", "code": "1", "children": ["北海道", "青森県", "岩手県", "宮城県", "山形県", "福島県", "秋田県"] },
        { "name": "関東", "value": "2", "code": "2", "children": ["茨城県", "栃木県", "群馬県", "埼玉県", "千葉県", "東京都", "神奈川県"] },
        { "name": "中部", "value": "3", "code": "3", "children": ["新潟県", "富山県", "石川県", "福井県", "山梨県", "長野県", "岐阜県", "静岡県", "愛知県"] },
        { "name": "近畿", "value": "4", "code": "4", "children": ["三重県", "滋賀県", "京都府", "大阪府", "兵庫県", "奈良県", "和歌山県" ] },
        { "name": "中国・四国", "value": "5", "code": "5", "children": ["鳥取県", "島根県", "岡山県", "広島県", "山口県", "徳島県", "香川県", "愛媛県", "高知県" ] },
        { "name": "九州", "value": "6", "code": "6", "children": ["福岡県", "佐賀県", "長崎県", "熊本県", "大分県", "宮崎県", "鹿児島県", "沖縄県" ] }
    ]
    return NextResponse.json({ hello })
}
```
```tsx:page.tsx
export default async function Page() {
    const res = await fetch(
        `${process.env.URL}/api/sample`, 
        {
            method: 'GET',
        }
    );
    const data = await res.json();
    console.log(data.hello);

    return (
        <h1>sample route</h1>
    )
}
```
```tsx:.env
URL="http://localhost:3000"
```
ブラウザで該当画面を表示すると、ターミナルにて画像のような出力が確認出来ると思います。
![スクリーンショット 2024-10-13 20.37.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/606316/b5f9409c-5596-d159-e479-9b18bbd8321c.png)

<a id="#Chapter6"></a>
# default.tsx
parallel routeでのFallback UIとして使用されるファイルです。
こちらは別記事で取り上げる予定です。

<a id="#reference"></a>
# 参考文献
- [Next 公式](https://nextjs.org/docs/getting-started/project-structure#routing-files)