Closed13

Next.js app router のドキュメント読む

H4KBH4KB

Getting Started

これからプロジェクトを作成する場合は app router がおすすめよ
app/ 作成して layout.tsx, page.tsx 作成すればそれがトップページになる
layout.tsx 忘れた場合、自動で作成されるよ

オプションだけど public/ フォルダーに画像やフォントなどの静的アセットいれな
app/ 下のコードから参照できるよ

プロジェクトストラクチャー にフォルダーやファイルの機能が載っている
この後の Routing で説明してくれそうなので、いったん飛ばして最後に戻ってくる

H4KBH4KB

Routing

今後の用語は以下に従う
Tree, Subtree, Leaf, Root, Segment を覚えれば良さそう


ファイル名の規則は以下になる

名前 機能
layout Segment とその子供のレイアウト設定ファイル
page Root 独自の UI ファイル
loading Segment とその子供の Loading 時のファイル?
Suspense で自動 fallback?
not-found Segment とその子供の NotFound 時のファイル
表示方法は?
error Segment とその子供の Error時のファイル
表示方法は?
global-error グローバルエラー時の UI
グローバルエラーとは?
route サーバーサイドの API エンドポイント
template 特別に再レンダリングされたレイアウト UI
?
default Parallel Routes のフォールバック UI

わからんやつあるけどリンクがあるので、今後説明出てきそう

上記以外の名前のファイルも app/ 下に作成できるよ

Segment を深くする場合はフォルダーをネストして作成(page route と同じ)
app/ 下フォルダーを作成しても page.js を作成しなければルーティングされない

Layout

レイアウトファイルはその Segment とその子供で共有され(デフォルト)、再レンダリングされない
Route Groups を使用すると共有レイアウトの範囲を設定できるらしい
デフォルトではサーバーサイドコンポーネント

/app のトップにレイアウトファイルは必須で、html, body が必須

Templates

Templates はレイアウトファイルと似ているが、新しいインスタンスを作成する
なので、Templates を使用しているページを開くと DOM が再作成され、ステートは保持されず、エフェクトが再同期される
useEffectuseState に依存する機能
レイアウト内で Suspense を定義した場合、root を初めて開いたときに表示されるが、ページを切り替えるときは表示されない
Templates に定義すると各ナビゲーションで表示される

H4KBH4KB

Linking and Navigating

<Link><a> タグの拡張で、ナビゲーションに使えるよ
usePathname()を使用すると、現在の URL のパス名を読み取ることができる

ナビゲーションで特定の箇所まで行きたい場合は、# をつけてな
useRouterでナビゲーションの push や replaceなどができるで (React router に似ているはず)

<Link> タグがビューポートに表示されるとプリフェッチされるで
router.prefetchでもプリフェッチすることができるで
基本 <Link>で良さそう?
プリフェッチも静的ルートと動的ルートで挙動が分かれる

静的ルート:デフォルトで true, ルート全体がプロジェクト&キャッシュ
動的ルート:デフォルトは automatic, loading.js ファイルまでの共有レイアウトのみがプリフェッチされ、30秒間キャッシュされる

Segment の子供間でナビゲートする場合親 Segment の Layout は保持されている

Next.js ではソフトナビゲーションを使用しておりナビゲーションによって、ページ全体がリロードされることはない

H4KBH4KB

Route Groups

フォルダー名をかっこで囲むことでルートグループを作成できる(folderName)
それぞれのルートグループで、異なるレイアウトを適応できるで

複数のルートグループを作成する場合は Top の layout.js 削除して、それぞれのルートグループで layout.js を作成してな
<html>, <body> を忘れずに
ルートグループまたがるとページ全体がロードされるで

H4KBH4KB

Dynamic Routes

動的セグメントは角括弧で囲むとできるで [folderName]
これは Page Router と変わらない気がする

generateStaticParamsを使用するとリクエスト時ではなくビルド時に静的ルートできる
動的セグメント内で自身を設定するよう

app/blog/[slug]/page.tsx
export async function generateStaticParams() {
  const posts = await fetch('https://.../posts').then((res) => res.json())
 
  return posts.map((post) => ({
    slug: post.slug, // ここで設定
  }))
}

[...folderName]を使用すると丸っとセグメントを取得できるで
app/shop/[...slug]/page.js/shop/a/b/c{ slug: ['a', 'b', 'c'] }

[[...folderName]] を使用すると上記の /shop も一致するパスに入るで

H4KBH4KB

Loading UI and Streaming

loading.js は Suspense を使って Loading 中の UI を定義できるで
Suspense と組み合わせるのと思ったが、自動で挿入されるっぽい

独自の Suspense を定義することも可能だよ
Suspense を使用したストリーミングをサポートしてるからね

ストリーミングとは?

その前に SSR の挙動な

  1. 初めにサーバー側でページに必要なデータ取得するで
  2. そのデータ使って HTML をレンダリングするで
  3. HTML, CSS, JS がクライアントに送られるで
  4. 良しなに hydrates するで

この流れの時1が重要になる
データがすべて取得できないと HTML 作成できないからな

ストリーミングは、ページの HTML を小さなチャンクに分割し、それを徐々に送信できるんや
そのおかげですべてのデータを取得するのを待たたずに、ページの一部が表示できるんや

ストリーミングはコンポーネントモデルと相性がいい
Header などはデータを待たずに送信できるし、コンポーネントの送信に優先順位をつけることもできる

上記を実現するのが <Suspense>
詳しくは React のドキュメントを読んでな

H4KBH4KB

Error Handling

こちらもセグメント内に error.tsxを定義すれば Error Boundary で自動的にラップされる(便利ー)
エラー境界より上のレイアウトはその状態を保持されるで

reset()を使用するとエラー境界の内容の再描画を実行することができるで

error は layout の下に位置するので、エラーが起きた場合 Layout を保持したままエラー表示するで
つまり Layout でのエラーはキャッチできないんや
トップレベルのエラーを処理したい場合は、global-error.js を作成してな
<html>, <body>を忘れないでね

H4KBH4KB

Parallel Routes

Parallel Routes を使用すると、複数のページを同じレイアウト内でレンダリングできるんや

そうすることで、ルートごとに Loading や Error 管理ができるんや
また条件付きレンダリングもできて 同じ URL で完全に分離されたコードが有効になるんや

ParalelRoutes は @folderName の名前で定義でき、同じセグメントのレイアウトに渡されるんや
@folderName はスロットって呼ばれるで
このスロットは URL 構造に影響しない

実は app/page.jsapp/@children/page.js なんや
だからレイアウトファイルで children が使えるんやな

URL に基づいてスロットのアクティブ状態?を回復できない場合、default.js に定義された UI をレンダリングするで
それが利用できない場合は 404 がレンダリングされるで

H4KBH4KB

Intercepting Routes

Intercepting Routes を使用すると、ユーザーが別のコンテキストに切り替えることなく、ルートのコンテンツを表示できる

は?

モーダルと一緒に用いることで、モーダル上で新たなページが表示できるよう

(..)folderNameで定義する

H4KBH4KB

Route Handlers

route.js を定義すると、カスタムリクエストハンドラーを作成できる
API リクエスト用?
なので page.js と同じ階層に定義できない
api/ 下に定義するのが良さそう?

H4KBH4KB

Middleware

Middleware を使うと、リクエストが完了する前にコードを実行することができる
送られてきたリクエストに基づいて、レスポンスを書き換えたり、リダイレクトしたり、リクエストやレスポンスのヘッダーを変更したり、直接レスポンスしたりすることで、レスポンスを変更することができる
プロキシサーバー的な?

Middleware はプロジェクト内のすべてのルートに対して呼び出される

  1. next.config.js の headers
  2. next.config.js の redirects
  3. Middleware
  4. next.config.js の beforeFiles
  5. Filesystem routes
  6. next.config.js の afterFiles
  7. Dynamic Routes
  8. next.config.js の fallback
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
 
// This function can be marked `async` if using `await` inside
export function middleware(request: NextRequest) {
  return NextResponse.redirect(new URL('/home', request.url))
}
 
export const config = {
  matcher: ['/about/:path*', '/dashboard/:path*'],
}

matcher は正規表現に対応している
NextResponse API を使用するとリダイレクトやレスポンスの書き換え
クッキーやヘッダーの設定ができる
また Middleware から直接レスポンスを返すこともできるで
サーバーへのリクエストを軽減できるんとちゃうか

import { NextRequest } from 'next/server'
import { isAuthenticated } from '@lib/auth'
 
// Limit the middleware to paths starting with `/api/`
export const config = {
  matcher: '/api/:function*',
}
 
export function middleware(request: NextRequest) {
  // Call our authentication function to check the request
  if (!isAuthenticated(request)) {
    // Respond with JSON indicating an error message
    return Response.json(
      { success: false, message: 'authentication failed' },
      { status: 401 }
    )
  }
}
H4KBH4KB

Project Organization and File Colocation

page.jsroute.jsを定義しない限り公開されないので、好きにフォルダーやファイルを作成できるで
_folderNameにすればプライベートフォルダーになって、page.jsを定義しても公開されへんで
基本的にはページ以外のフォルダーを作成したい場合、プライベートフォルダーにしておくのが良さそう?
Next.js の将来的な名前衝突も避けられそうやしな

例見たらそんなことなかった
普通に componetsフォルダー作成してた

H4KBH4KB

Data Fetching

Next.js はネイティブの fetch API を拡張してるで
自動的にメモするからな
ただ Route ハンドラー(route.js)の fetch はメモされないで、React のコンポーネントツリーでないからな
cokies や headers にも便利な関数用意してるで

デフォルトでは fetch は自動でキャッシュされるで
POSTもキャッシュするからな
Route ハンドラーは別や

再リクエストするには2つの方法があるで

fetch 関数に revalidate を設定すれば、その秒数経ってたら再リクエストするで

fetch('https://...', { next: { revalidate: 3600 } })

他に revalidatePathrevalidateTagを使って、変わってたら再リクエストするで
React Query みたいな感じ?

cach: 'no-store'に設定したりすることでキャッシュを無効にできるで

このスクラップは2024/02/11にクローズされました