Open11

今更、Next.js の App Router について勉強する

KenjiKenji

概要

  • Next.js の公式ドキュメントを読む
  • 読んだ感想を書く

https://nextjs.org/docs

Routing

ファイルシステムのルーティングで、Server Components や Intercepting Routing / Parallel Routes を主にキャッチアップしたい

Rendering

App Router でレンダリングがどのように変化したのかが気になっている

Data Fetching

caching や revalidation は理解するのに、時間かかりそうだから、飛ばすかもしれない
GraphQL の Fragment Colocation で行っていた「コンポーネント内にデータ取得を閉じこめる」という発想は React Server Component によって GraphQL 無しでもできるようになったからなー。バックエンド API や DB が同じネットワーク内にある BFF で行われるのでリクエスト一発で取る必要も特になくなる。新しく勉強しなくても良さそうなのかな

https://nextjs.org/docs#main-features

KenjiKenji

Routing

https://nextjs.org/docs/app/building-your-application/routing

  • Tree: A convention for visualizing a hierarchical structure. For example, a component tree with parent and children components, a folder structure, etc.
  • Subtree: Part of a tree, starting at a new root (first) and ending at the leaves (last).
  • Root: The first node in a tree or subtree, such as a root layout.
  • Leaf: Nodes in a subtree that have no children, such as the last segment in a URL path.

App Router の方が直感的に理解できそう。

A file-system based router

ドキュメントの冒頭に、書かれていたの納得。

Terminology for URL Anatomy
URL Segment: Part of the URL path delimited by slashes.
URL Path: Part of the URL that comes after the domain (composed of segments).

Good to know: The App Router takes priority over the Pages Router. Routes across directories should not resolve to the same URL path and will cause a build-time error to prevent a conflict.

App Router と Page Router を共存できるみたいね

By default, components inside app are React Server Components. This is a performance optimization and allows you to easily adopt them, and you can also use Client Components.

Client Components を使おうとしたら、use client を宣言しないといけないみたい。JavaScript を極力控えないといけないみたいね。プログレッシブエンハンスメントだね

Roles of Folders and Files

フォルダ構成の設計、今までと違うようになるね。でも直感的。

Component Hierarchy

Error Boundary って React で提供してくれないのかな。ライブラリを使わないといけない。いけなくない?

Colocation

コードの肥大化を回避するために、あるのかな

  • Parallel Routes: Allow you to simultaneously show two or more pages in the same view that can be navigated independently. You can use them for split views that have their own sub-navigation. E.g. Dashboards.
  • Intercepting Routes: Allow you to intercept a route and show it in the context of another route. You can use these when keeping the context for the current page is important. E.g. Seeing all tasks while editing one task or expanding a photo in a feed.

ここは、深掘りたい箇所だな!

Pages and Layouts

The special files layout.js, page.js, and template.js allow you to create UI for a route. This page will guide you through how and when to use these special files.

layout.js, pages.js,template.js はどんな役割で分割されてるんだろう
読み進めていくと、ここらへん読み解けていけそう

Pages

A page is UI that is unique to a route. You can define a page by default exporting a component from a page.js file.

独自 path での表示みたいだね

The .js, .jsx, or .tsx file extensions can be used for Pages.

.ts は難しいのかな

A page is always the leaf of the route subtree.

完全に理解した

Pages are Server Components by default, but can be set to a Client Component.

use client をつける負担があるのか

Layouts

A layout is UI that is shared between multiple routes. On navigation, layouts preserve state, remain interactive, and do not re-render. Layouts can also be nested.

これは、colocation の概念としてなのかな
preserve state って本当だろうか、Layououts は re-render されないみたいな意味かな

  • Root Layout

    • html や body タグは含まれていないといけないみたい
    • server から返ってくる
  • Nesting Layouts

    • 同層ディレクトリに layouts.js が存在しないといけない
    • app/layout.js, app/dashboard/layout.js のように nest しても大丈夫みたい

Templates

テンプレートとはなんなんだろうか。

Templates are similar to layouts in that they wrap each child layout or page. Unlike layouts that persist across routes and maintain state, templates create a new instance for each of their children on navigation. This means that when a user navigates between routes that share a template, a new instance of the component is mounted, DOM elements are recreated, state is not preserved, and effects are re-synchronized.

Client Component が前提の概念なのかな。必要なさそうだけど。状態は保持されない。同期されないみたいだな。

A template can be defined by exporting a default React component from a template.js file. The component should accept a children prop.

export default function Template({ children }: { children: React.ReactNode }) {
  return <div>{children}</div>
}
<Layout>
  {/* Note that the template is given a unique key. */}
  <Template key={routeParam}>{children}</Template>
</Layout>

Next.js has a Metadata API that can be used to define your application metadata (e.g. meta and link tags inside your HTML head element) for improved SEO and web shareability.

There are two ways you can add metadata to your application:

Config-based Metadata: Export a static metadata object or a dynamic generateMetadata function in a layout.js or page.js file.
File-based Metadata: Add static or dynamically generated special files to route segments.
With both these options, Next.js will automatically generate the relevant <head> elements for your pages. You can also create dynamic OG images using the ImageResponse constructor.

Both static and dynamic metadata through generateMetadata are only supported in Server Components.

type safe なルーティングや generateMetadata といい App Router を前提とする機能が多い気がする

https://nextjs.org/docs/app/building-your-application/optimizing/metadata

This means metadata with nested fields such as openGraph and robots that are defined in an earlier segment are overwritten by the last segment to define them.

openGraph がなにかを理解していない。(理解するために、何かを読んでない)

Dynamic Image Generation

Edge Runtime ってなに
The Edge Runtime is ideal if you need to deliver dynamic, personalized content at low latency with small, simple functions.
https://nextjs.org/docs/app/building-your-application/rendering/edge-and-nodejs-runtimes#edge-runtime

Linking and Navigating

There are four ways to navigate between routes in Next.js:
Using the <Link> Component
Using the useRouter hook (Client Components)
Using the redirect function (Server Components)
Using the native History API

Caching
ここ、難しそう!

Partial Rendering

Loading UI and Streaming

The special file loading.js helps you create meaningful Loading UI with React Suspense.
https://react.dev/reference/react/Suspense

Concurrent Mode の機能と並行で使う感じ。loading.js はなんだろう。ただのローディング UI じゃないのかな

Instant Loading States

You can pre-render loading indicators such as skeletons and spinners, or a small but meaningful part of future screens such as a cover photo, title, etc.

loading.js 必要かなって思っちゃた。ただの Concurrent Mode だな

Recommendation: Use the loading.js convention for route segments (layouts and pages) as Next.js optimizes this functionality.

大きい Component based で loading.js を挟むと良さそうなのね。

Streaming with Suspense
loading.js で Suspence Boundary を使えるみたいだなー

Streaming SSR については、この記事が理解が捗りそうだ
https://www.patterns.dev/react/streaming-ssr

KenjiKenji

Error Handling

error.js は React Error Boundary の wrapper 関数なのかな
だとしたら、宣言的に状態を定義してるだけなのかな。そこまで難しくなさそう。

Errors bubble up to the nearest parent error boundary. This means an error.js file will handle errors for all its nested child segments. More or less granular error UI can be achieved by placing error.js files at different levels in the nested folders of a route.

あー、想定してないエラー状態を見過ごすことがありそうだから。根本から宣言する必要があるみたい。

To handle errors within the root layout or template, use a variation of error.js called global-error.js

書いてあったわ。

the Error object forwarded to the client only includes a generic message and digest property.
https://nextjs.org/docs/app/building-your-application/routing/error-handling#handling-server-errors

ここは、JavaScript の辛いとこなのかな。ちょっと再度手を動かして確かめてみよ

KenjiKenji

Route Group

In the app directory, nested folders are normally mapped to URL paths. However, you can mark a folder as a Route Group to prevent the folder from being included in the route's URL path.

フォルダ構成がルート構成になるらしい。

a route is not publicly accessible until a page.js or route.js file is added to a route segment.

ファイルは個ロケーションとして守られた状態になる

Private Folders

これは、便利。React の場合だと Plugin でできそう。import access かな

https://nextjs.org/docs/app/building-your-application/caching#request-memoization

KenjiKenji

Parallel Routes

Parallel Routes allows you to simultaneously or conditionally render one or more pages within the same layout. They are useful for highly dynamic sections of an app, such as dashboards and feeds on social sites.

Slots
Parallel routes are created using named slots. Slots are defined with the @folder convention. For example, the following file structure defines two slots: @analytics and @team:

Modals
Parallel Routes can be used together with Intercepting Routes to create modals. This allows you to solve common challenges when building modals, such as:

  • Making the modal content shareable through a URL.
  • Preserving context when the page is refreshed, instead of closing the modal.
  • Closing the modal on backwards navigation rather than going to the previous route.
  • Reopening the modal on forwards navigation.
    Consider the following UI pattern, where a user can open a login modal from a layout using client-side navigation, or access a separate /login page:

Intercepting Routes は Parallel Routes と併用するみたいだね。

https://github.com/vercel/next.js/pull/64086

KenjiKenji

Middleware

Middleware allows you to run code before a request is completed. Then, based on the incoming request, you can modify the response by rewriting, redirecting, modifying the request or response headers, or responding directly.

パフォーマンス、セキュリティ、UXの向上するために存在するみたい。
具体的にどんなことが期待されるんだろう。

向いてること

  • 認証と認可
  • サーバーサイドリダイレクト
  • パスの書き換え
  • ログと分析
  • フィーチャーフラグ

向いていないこと

  • 複雑なデータ取得と操作
  • 負荷の高い計算処理
  • セッション管理
  • DB の直接実行

できること

  • リクエストを別のURLにリダイレクトする
  • 応答を書き換えて指定したURLを表示する
  • APIルート、getServerSideProps、書き換え先でリクエストヘッダーを設定する
  • 応答クッキーを設定する
  • 応答ヘッダーを設定する
KenjiKenji

Data Fetching

データ取得の方法

  1. サーバー側での取得:

    • 標準のfetchを使用
    • サードパーティのライブラリを使用
  2. クライアント側での取得:

    • ルートハンドラーを経由
    • サードパーティのライブラリを使用

キャッシュについて

  • Next.jsはサーバー上でfetchの戻り値を自動的にキャッシュします。
  • キャッシュのデフォルト設定はforce-cacheですが、例外的にPOSTメソッドを使用するルートハンドラーやサーバーアクション内での使用時はキャッシュされません。

データの再検証

  • 時間ベースの revalidate: 一定時間が経過した後にデータを自動的に revalidate。
  • オンデマンドの revalidate: 特定のイベント(例えばフォームの提出)に基づいてデータを手動で再検証。

エラーハンドリングと再検証

  • revalidate 中にエラーが発生した場合でも、最後に成功したデータがキャッシュから提供され続けます。
  • 次のリクエスト時にデータの再検証が再試行されます。

データキャッシングのオプトアウト

  • no-storeをfetchリクエストに設定することでキャッシングを無効にできます。
  • POSTメソッドを使用するルートハンドラーでのfetchリクエストや、AuthorizationCookieヘッダーを使用するリクエストではキャッシュされません。
KenjiKenji

Rendering

React と Next.js はハイブリッドのレンダリングができる。任意の箇所を server と client を選択できる。environment, strategies, runtimes をする

基礎

  • Environment
  • Request-Response Lifecycle
  • Network Boundary

same language, same framework で継ぎ目がない状態で client で server 書き分ける
"use client" と "use server" で Network Boundary を選択できるようになる

Server Components

レンダリング戦略には複数存在するが大別すると3つある。

  • Static Rendering
  • Dynamic Rendering
  • Streaming

なぜ、Server Components なのか

  • データ取得
  • キャッシュ
    • サーバー上でレンダリングされたデータ取得やリクエストを軽量化
  • パフォーマンス
    • Client JavaScript の総量が減る
      • 低スペックデバイスユーザに有効
      • インターネット環境が悪いユーザに有効
  • 初期ページロードと最初に表示されるコンテンツ
    • サーバ上で HTML を生成して、逐次 Client JavaScript を取得する
  • Streaming
    • WIP

orchestrate rendering

この言葉が気になっている

react.dev で orchestrate rendering
https://react.dev/reference/rules/react-calls-components-and-hooks

Each chunk is rendered in two steps:
React renders Server Components into a special data format called the React Server Component Payload (RSC Payload).
Next.js uses the RSC Payload and Client Component JavaScript instructions to render HTML on the server.
Then, on the client:
The HTML is used to immediately show a fast non-interactive preview of the route - this is for the initial page load only.
The React Server Components Payload is used to reconcile the Client and Server Component trees, and update the DOM.
The JavaScript instructions are used to hydrate Client Components and make the application interactive.

Server Rendering Strategies

render のタイミングは大別すると3つある

  • build
  • server
  • client

Static Rendering

  • build のタイミングでレンダリングされる
  • 個人情報が載っていないページに向いている
    • 静的なブログ
    • 商品ページ

Dynamic Rendering

  • request のタイミングでレンダリングされる
    • cookies, headers
    • URL search, searchParams

Streaming

サーバーから徐々に UI がレンダリングされる。React Suspense、Loading UI and Streaming

Client Rendering

use client を宣言しなければ使用できない。

  • Client Components
    • Interactivity
      • state
      • effects
      • event listeners
    • Browser API
      • geolocation
      • localStorage

https://github.com/reactwg/server-components/discussions/4

Runtimes

  • Node.js Runtime
    • タイミングはレンダリングするとき
  • Edge Runtime
    • ミドルウェアでリダイレクト、リライトやヘッダーを設定するとき