diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index dd84ea7..b5c68e5 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -4,7 +4,6 @@ about: Create a report to help us improve title: '' labels: '' assignees: '' - --- **Describe the bug** @@ -12,6 +11,7 @@ A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: + 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' @@ -24,15 +24,17 @@ A clear and concise description of what you expected to happen. If applicable, add screenshots to help explain your problem. **Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] + +- OS: [e.g. iOS] +- Browser [e.g. chrome, safari] +- Version [e.g. 22] **Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] + +- Device: [e.g. iPhone6] +- OS: [e.g. iOS8.1] +- Browser [e.g. stock browser, safari] +- Version [e.g. 22] **Additional context** Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/issue_template.md b/.github/ISSUE_TEMPLATE/issue_template.md index 4be775c..e04efde 100644 --- a/.github/ISSUE_TEMPLATE/issue_template.md +++ b/.github/ISSUE_TEMPLATE/issue_template.md @@ -4,7 +4,6 @@ about: Standard issue template for Nextjs-docs-ja title: '' labels: '' assignees: '' - --- #### Description diff --git a/docs/01-app/01-getting-started/02-layouts-and-pages.mdx b/docs/01-app/01-getting-started/02-layouts-and-pages.mdx new file mode 100644 index 0000000..bdcf05e --- /dev/null +++ b/docs/01-app/01-getting-started/02-layouts-and-pages.mdx @@ -0,0 +1,303 @@ +--- +title: 'レイアウトとページを作成する方法' +nav_title: 'レイアウトとページ' +description: 'Next.js アプリケーションでレイアウトとページを作成し、それらをリンクする方法を学びます。' +related: + links: + - 'app/api-reference/file-conventions/layout' + - 'app/api-reference/file-conventions/page' + - 'app/api-reference/components/link' +--- + +Next.jsは**ファイルシステムベースのルーティング**を使用しており、フォルダとファイルを使ってルートを定義することができます。このページでは、レイアウトとページを作成し、それらをリンクする方法を説明します。 + +## ページを作成する {#creating-a-page} + +**ページ**とは、特定のルートでレンダリングされるUIです。ページを作成するには、`app`ディレクトリ内に[`page`ファイル](/docs/app/api-reference/file-conventions/page)を追加し、Reactコンポーネントをデフォルトエクスポートします。たとえば、インデックスページ(`/`)を作成するには次のようにします。 + +page.js 特殊ファイル + + + + +```tsx title="app/page.tsx" switcher +export default function Page() { + return

Hello Next.js!

+} +``` + +
+ + +```jsx title="app/page.js" switcher +export default function Page() { + return

Hello Next.js!

+} +``` + +
+
+ +## レイアウトを作成する {#creating-a-layout} + +レイアウトは、複数のページ間で**共有**されるUIです。ナビゲーション時にレイアウトは状態を保持し、対話可能で、再レンダリングされません。 + +[`layout`ファイル](/docs/app/api-reference/file-conventions/layout)からReactコンポーネントをデフォルトエクスポートすることでレイアウトを定義できます。このコンポーネントは、`children` propを受け入れるべきで、それはページや他の[レイアウト](#nesting-layouts)でありえます。 + +たとえば、インデックスページを子として受け入れるレイアウトを作成するには、`app`ディレクトリ内に`layout`ファイルを追加します。 + +layout.js 特殊ファイル + + + + +```tsx title="app/layout.tsx" switcher +export default function DashboardLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + + + {/* レイアウト UI */} + {/* ページやネストしたレイアウトをレンダリングしたい場所に children を置きます */} +
{children}
+ + + ) +} +``` + +
+ + +```jsx title="app/layout.js" switcher +export default function DashboardLayout({ children }) { + return ( + + + {/* レイアウト UI */} + {/* ページやネストしたレイアウトをレンダリングしたい場所に children を置きます */} +
{children}
+ + + ) +} +``` + +
+
+ +上記のレイアウトは、`app`ディレクトリのルートに定義されているため、[root レイアウト](/docs/app/api-reference/file-conventions/layout#root-layouts)と呼ばれます。root レイアウトは**必須**であり、`html`タグと`body`タグを含む必要があります。 + +## ネストしたルートを作成する {#creating-a-nested-route} + +ネストしたルートは、複数のURLセグメントから構成されるルートです。たとえば、`/blog/[slug]`ルートは3つのセグメントで構成されています: + +- `/` (Root セグメント) +- `blog` (セグメント) +- `[slug]` (Leaf セグメント) + +Next.js では: + +- **フォルダ**は、URLセグメントにマップされるルートセグメントを定義するために使用されます。 +- **ファイル**(`page`や`layout`のような)を使用して、セグメントに表示するUIを作成します。 + +ネストしたルートを作成するには、フォルダをネストすることができます。たとえば、`/blog`ルートを追加するには、`app`ディレクトリ内に`blog`というフォルダを作成します。次に、`/blog`を公開するために`page`ファイルを追加します。 + +ファイル階層を示す blog フォルダと page.js ファイル + + + + +```tsx title="app/blog/page.tsx" switcher +import { getPosts } from '@/lib/posts' +import { Post } from '@/ui/post' + +export default async function Page() { + const posts = await getPosts() + + return ( + + ) +} +``` + + + + + + +```jsx title="app/blog/[slug]/page.js" switcher +import { getPosts } from '@/lib/posts' +import { Post } from '@/ui/post' + +export default async function Page() { + const posts = await getPosts() + + return ( + + ) +} +``` + + + + +フォルダをさらにネストしてネストしたルートを作成し続けることができます。たとえば、特定のブログ投稿のルートを作成するには、`blog`内に新しい`[slug]`フォルダを作成し、`page`ファイルを追加します。 + +ファイル階層を示す blog フォルダでネストされた slug フォルダと page.js ファイル + + + + +```tsx title="app/blog/[slug]/page.tsx" switcher +function generateStaticParams() {} + +export default function Page() { + return

Hello, Blog Post Page!

+} +``` + +
+ + +```jsx title="app/blog/[slug]/page.js" switcher +function generateStaticParams() {} + +export default function Page() { + return

Hello, Blog Post Page!

+} +``` + +
+
+ +> **Good to know**: フォルダ名を角括弧で囲む(例:`[slug]`)と、データから複数のページを生成する特別な**dynamic route segment**が作成されます。これはブログ投稿や商品ページなどに便利です。[動的セグメント](/docs/app/building-your-application/routing/dynamic-routes)について詳しく学びましょう。 + +## レイアウトをネストする {#nesting-layouts} + +デフォルトでは、フォルダ階層内のレイアウトもネストされており、`children` propを通じて子レイアウトをラップします。特定のルートセグメント(フォルダ)内に`layout`を追加することでレイアウトをネストできます。 + +たとえば、`/blog`ルートに対するレイアウトを作成するには、`blog`フォルダ内に新しい`layout`ファイルを追加します。 + +root レイアウトがブログレイアウトをラップしているファイル階層 + + + + +```tsx title="app/blog/layout.tsx" switcher +export default function BlogLayout({ + children, +}: { + children: React.ReactNode +}) { + return
{children}
+} +``` + +
+ + +```jsx title="app/blog/layout.js" switcher +export default function BlogLayout({ children }) { + return
{children}
+} +``` + +
+
+ +上記2つのレイアウトを組み合わせると、root layout (`app/layout.js`) が blog layout (`app/blog/layout.js`) をラップし、blog (`app/blog/page.js`) とブログ投稿ページ (`app/blog/[slug]/page.js`) をラップします。 + +## ページ間のリンク {#linking-between-pages} + +ルート間をナビゲートするには、[``コンポーネント](/docs/app/api-reference/components/link)を使用できます。``は、プリフェッチとクライアントサイドのナビゲーションを提供するためにHTML `` タグを拡張する、Next.js組み込みのコンポーネントです。 + +たとえば、ブログ投稿のリストを生成するには、`next/link`から``をインポートし、コンポーネントに`href` propを渡します。 + + + + +```tsx title="app/ui/post.tsx" highlight={1,6} switcher +import Link from 'next/link' + +export default async function Post({ post }) { + const posts = await getPosts() + + return ( +
    + {posts.map((post) => ( +
  • + {post.title} +
  • + ))} +
+ ) +} +``` + +
+ + +```jsx title="app/ui/post.js" highlight={1,6} switcher +import Link from 'next/link' + +export default async function Post({ post }) { + const posts = await getPosts() + + return ( +
    + {posts.map((post) => ( +
  • + {post.title} +
  • + ))} +
+ ) +} +``` + +
+
+ +``は、Next.jsアプリケーションでルート間を移動するための主要かつ推奨される方法です。しかし、より高度なナビゲーションには[`useRouter`フック](/docs/app/api-reference/functions/use-router)を使うこともできます。 diff --git a/docs/01-app/01-getting-started/02-project-structure.mdx b/docs/01-app/01-getting-started/03-project-structure.mdx similarity index 100% rename from docs/01-app/01-getting-started/02-project-structure.mdx rename to docs/01-app/01-getting-started/03-project-structure.mdx diff --git a/docs/01-app/01-getting-started/04-images-and-fonts.mdx b/docs/01-app/01-getting-started/04-images-and-fonts.mdx new file mode 100644 index 0000000..16ab70f --- /dev/null +++ b/docs/01-app/01-getting-started/04-images-and-fonts.mdx @@ -0,0 +1,435 @@ +--- +title: '画像とフォントを最適化する方法' +nav_title: 'Images and Fonts' +description: 'Next.jsで画像とフォントを最適化する方法を学ぶ' +related: + links: + - app/api-reference/components/font + - app/api-reference/components/image +--- + +Next.jsはパフォーマンスとユーザーエクスペリエンスを向上させるために、自動的な画像とフォントの最適化機能を備えています。このページでは、それらを使い始める方法を解説します。 + +## 静的アセットの処理 {#handling-static-assets} + +画像やフォントのような静的ファイルは、ルートディレクトリの`public`というフォルダに保存できます。`public`内のファイルはベースURL(`/`)からコードによって参照できます。 + +アプリとパブリックフォルダを示すフォルダ構造 + +## 画像の最適化 {#optmizing-images} + +Next.jsの[``](/docs/app/building-your-application/optimizing/images)コンポーネントはHTMLの``要素を拡張して次の機能を提供します: + +- **サイズの最適化:** WebPやAVIFのような現代的な画像フォーマットを使用して、各デバイスに対して適切なサイズの画像を自動的に提供します +- **視覚的安定性:** 画像の読み込み中に[レイアウトシフト](https://nextjs.org/learn/seo/web-performance/cls)を自動的に防ぎます +- **高速なページロード:** ブラウザのネイティブラジーローディングを利用して、ビューポートに入ったときにのみ画像を読み込みます。また、ぼかしプレースホルダーをオプションで使用できます +- **アセットの柔軟性:** リモートサーバーに保存されている画像であっても、オンデマンドで画像サイズを変更できます + +``を使い始めるには、`next/image`からインポートしてコンポーネント内でレンダリングします。 + + + + +```tsx title="app/page.tsx" switcher +import Image from 'next/image' + +export default function Page() { + return +} +``` + + + + +```jsx title="app/page.js" switcher +import Image from 'next/image' + +export default function Page() { + return +} +``` + + + + +`src`プロパティは[ローカル](#local-images)または[リモート](#remote-images)な画像を指定できます。 + +### ローカル画像 {#local-images} + +ローカル画像を使用するには、`public`フォルダから`.jpg`、`.png`、または`.webp`画像ファイルを`import`します。 + + + + +```tsx title="app/page.tsx" switcher +import Image from 'next/image' +import profilePic from './me.png' + +export default function Page() { + return ( + 著者の写真 + ) +} +``` + + + + +```jsx title="app/page.js" switcher +import Image from 'next/image' +import profilePic from './me.png' + +export default function Page() { + return ( + 著者の写真 + ) +} +``` + + + + +Next.jsはインポートされたファイルに基づいて画像の本来の[`width`](/docs/app/api-reference/components/image#width)と[`height`](/docs/app/api-reference/components/image#height)を自動的に決定します。これらの値は画像の比率を決定し、画像の読み込み中の[Cumulative Layout Shift](https://nextjs.org/learn/seo/web-performance/cls)を防ぐために使用されます。 + +### リモート画像 {#remote-images} + +リモート画像を使用するには、`src`プロパティにURL文字列を指定します。 + + + + +```tsx title="app/page.ts" switcher +import Image from 'next/image' + +export default function Page() { + return ( + 著者の写真 + ) +} +``` + + + + +```jsx title="app/page.js" switcher +import Image from 'next/image' + +export default function Page() { + return ( + 著者の写真 + ) +} +``` + + + + +Next.jsはビルドプロセス中にリモートファイルにアクセスできないため、[`width`](/docs/app/api-reference/components/image#width)、[`height`](/docs/app/api-reference/components/image#height)およびオプションの[`blurDataURL`](/docs/app/api-reference/components/image#blurdataurl)プロップを手動で提供する必要があります。`width`と`height`属性は画像の正しいアスペクト比を推測し、画像の読み込みに伴うレイアウトシフトを避けるために使用されます。ただし、`width`と`height`は画像ファイルのレンダリングサイズを決定するものではありません。 + +その後、リモートサーバーからの画像を安全に許可するために、`next.config.js`にサポートされるURLパターンのリストを定義する必要があります。不正使用を防ぐために、できるだけ具体的に記述してください。たとえば、以下の構成は特定のAWS S3バケットからのみ画像を許可します: + + + + +```ts title="next.config.ts" switcher +import { NextConfig } from 'next' + +const config: NextConfig = { + images: { + remotePatterns: [ + { + protocol: 'https', + hostname: 's3.amazonaws.com', + port: '', + pathname: '/my-bucket/**', + search: '', + }, + ], + }, +} + +export default config +``` + + + + +```js title="next.config.js" switcher +module.exports = { + images: { + remotePatterns: [ + { + protocol: 'https', + hostname: 's3.amazonaws.com', + port: '', + pathname: '/my-bucket/**', + search: '', + }, + ], + }, +} +``` + + + + +Image Optimizationについてさらに詳しくは[APIリファレンス](/docs/app/api-reference/components/image)をご覧ください。 + +## フォントの最適化 {#optimizing-fonts} + +[`next/font`](/docs/app/api-reference/components/font)モジュールは、プライバシーとパフォーマンスを向上させるためにフォントを自動的に最適化し、外部ネットワークリクエストを削除します。 + +これにはあらゆるフォントファイルの**組み込みの自動セルフホスティング**が含まれます。これにより、レイアウトシフトなしでWebフォントを最適に読み込むことができます。 + +`next/font`を使用し始めるには、([Google](#google-fonts)フォントを使用するか[ローカル](#local-fonts)フォントを使用するかによって)`next/font/local`または`next/font/google`からインポートし、適切なオプションを使用して関数として呼び出し、フォントを適用したい要素の`className`を設定します。 + + + + +```tsx title="app/layout.tsx" switcher +import { Geist } from 'next/font/google' + +const geist = Geist({ + subsets: ['latin'], +}) + +export default function Layout({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ) +} +``` + + + + +```jsx title="app/layout.js" switcher +import { Geist } from 'next/font/google' + +const geist = Geist({ + subsets: ['latin'], +}) + +export default function Layout({ children }) { + return ( + + {children} + + ) +} +``` + + + + +### Googleフォント {#google-fonts} + +任意のGoogleフォントを自動的にセルフホストできます。フォントはデプロイメントに含まれており、デプロイメントと同じドメインから提供されます。**ブラウザによってGoogleにリクエストは送信されません。** + +Googleフォントの使用を開始するには、`next/font/google`から関数としてインポートします。 + + + + +```tsx title="app/layout.tsx" switcher +import { Inter } from 'next/font/google' + +const inter = Inter({ + subsets: ['latin'], +}) + +export default function RootLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + + {children} + + ) +} +``` + + + + +```jsx title="app/layout.js" switcher +import { Inter } from 'next/font/google' + +const inter = Inter({ + subsets: ['latin'], +}) + +export default function RootLayout({ children }) { + return ( + + {children} + + ) +} +``` + + + + +最高のパフォーマンスと柔軟性を得るために[可変フォント](https://fonts.google.com/variablefonts)を使用することをお勧めしますが、可変フォントを使用できない場合は、**ウェイトを指定する必要があります:** + + + + +```tsx title="app/layout.tsx" switcher +import { Roboto } from 'next/font/google' + +const roboto = Roboto({ + weight: '400', + subsets: ['latin'], +}) + +export default function RootLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + + {children} + + ) +} +``` + + + + +```jsx title="app/layout.js" switcher +import { Roboto } from 'next/font/google' + +const roboto = Roboto({ + weight: '400', + subsets: ['latin'], +}) + +export default function RootLayout({ children }) { + return ( + + {children} + + ) +} +``` + + + + +### ローカルフォント {#local-fonts} + +ローカルフォントを使用するには、`next/font/local`をインポートし、[`public`フォルダ](#handling-static-assets)にあるローカルフォントファイルの`src`を指定します。 + + + + +```tsx title="app/layout.tsx" switcher +import localFont from 'next/font/local' + +const myFont = localFont({ + src: './my-font.woff2', +}) + +export default function RootLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + + {children} + + ) +} +``` + + + + +```jsx title="app/layout.js" switcher +import localFont from 'next/font/local' + +const myFont = localFont({ + src: './my-font.woff2', +}) + +export default function RootLayout({ children }) { + return ( + + {children} + + ) +} +``` + + + + +単一のフォントファミリに対して複数のファイルを使用したい場合、`src`は配列にすることができます: + +```js +const roboto = localFont({ + src: [ + { + path: './Roboto-Regular.woff2', + weight: '400', + style: 'normal', + }, + { + path: './Roboto-Italic.woff2', + weight: '400', + style: 'italic', + }, + { + path: './Roboto-Bold.woff2', + weight: '700', + style: 'normal', + }, + { + path: './Roboto-BoldItalic.woff2', + weight: '700', + style: 'italic', + }, + ], +}) +``` + +Font Optimizationについてさらに詳しくは[APIリファレンス](/docs/app/api-reference/components/font)をご覧ください。 diff --git a/docs/01-app/01-getting-started/05-css-and-styling.mdx b/docs/01-app/01-getting-started/05-css-and-styling.mdx new file mode 100644 index 0000000..b3fa562 --- /dev/null +++ b/docs/01-app/01-getting-started/05-css-and-styling.mdx @@ -0,0 +1,650 @@ +--- +title: 'アプリケーションでCSSを使用する方法' +nav_title: 'CSSとスタイリング' +description: 'Next.jsアプリケーションにCSSとスタイリングを追加する方法を学びましょう。' +related: + links: + - 'app/api-reference/config/next-config-js/sassOptions' + - 'architecture/nextjs-compiler' +--- + +Next.jsは、あなたのアプリケーションでCSSを使用するためのいくつかの方法を提供しています; + +- [CSS Modules](#css-modules) +- [グローバルCSS](#global-css) +- [Tailwind CSS](#tailwind-css) +- [Sass](#sass) +- [CSS-in-JS](#css-in-js) +- [外部スタイルシート](#external-stylesheets) + +このページでは、これらのアプローチのそれぞれの使用方法について案内します。 + +## CSS Modules {#css-modules} + +CSS Modulesは、ユニークなクラス名を生成することでCSSをローカルスコープにします。これにより、異なるファイルで同じクラスを使用する際に衝突を心配する必要がありません。 + +CSS Modulesの使用を開始するには、`.module.css`拡張子を持つ新しいファイルを作成して、それを`app`ディレクトリ内のコンポーネントにインポートします: + +```css title="app/blog/styles.module.css" +.blog { + padding: 24px; +} +``` + + + + +```tsx title="app/blog/page.tsx" switcher +import styles from './styles.module.css' + +export default function Page({ children }: { children: React.ReactNode }) { + return
{children}
+} +``` + +
+ + +```jsx title="app/blog/page.js" switcher +import styles from './styles.module.css' + +export default function Page({ children }) { + return
{children}
+} +``` + +
+
+ +> **Good to know:** +> +> - CSS Modulesは、`.module.css`と`.module.sass`拡張子を持つファイルに対してのみ有効です。 +> - 本番環境では、すべてのCSS Moduleファイルは、自動的に結合されミニファイされ、コード分割された`.css`ファイルに変換されます。 +> - これらの`.css`ファイルは、アプリケーションの高速な実行パスを示し、アプリケーションの描画に必要な最小限のCSSのみが読み込まれるようにします。 + +## グローバルCSS {#global-css} + +グローバルCSSを使用して、アプリケーション全体にスタイルを適用することができます。 + +グローバルスタイルを使用するには、新しいCSSファイルを作成します。例えば、`app/global.css`: + +```css title="app/global.css" +body { + padding: 20px 20px 60px; + max-width: 680px; + margin: 0 auto; +} +``` + +ファイルをroot レイアウト (`app/layout.js`) にインポートして、アプリケーションの**すべてのルート**にスタイルを適用します: + + + + +```tsx title="app/layout.tsx" switcher +// アプリケーションのすべてのルートにこれらのスタイルが適用されます +import './global.css' + +export default function RootLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + + {children} + + ) +} +``` + + + + +```jsx title="app/layout.js" switcher +// アプリケーションのすべてのルートにこれらのスタイルが適用されます +import './global.css' + +export default function RootLayout({ children }) { + return ( + + {children} + + ) +} +``` + + + + +> **Good to know:** グローバルスタイルは、`app`ディレクトリ内の任意のレイアウト、ページ、またはコンポーネントにインポートできます。ただし、Next.jsはReactの組み込みのスタイルシートサポートを使用してSuspenseと統合しているため、新しいReact機能にCSS-in-JSを使用する場合、スタイルシートがルート間でナビゲートする際に削除されません。このため、*本当に*グローバルなCSSにはグローバルスタイルを使用し、スコープ化されたCSSには[CSS Modules](#css-modules)を使用することをお勧めします。 + +## Tailwind CSS {#tailwind-css} + +[Tailwind CSS](https://tailwindcss.com/)は、Next.jsとシームレスに統合されるユーティリティファーストのCSSフレームワークです。 + +### Tailwindのインストール {#installing-tailwind} + +Tailwindを使用するには、まずTailwind CSSパッケージをインストールし、`init`コマンドを実行して`tailwind.config.js`と`postcss.config.js`ファイルを生成します: + +```bash title="Terminal" +npm install -D tailwindcss postcss autoprefixer +npx tailwindcss init -p +``` + +### Tailwindの設定 {#configuring-tailwind} + +Tailwind設定ファイル内で、Tailwindクラス名を使用するファイルのパスを追加します: + + + + +```ts title="tailwind.config.ts" switcher +import type { Config } from 'tailwindcss' + +const config: Config = { + content: [ + './app/**/*.{js,ts,jsx,tsx,mdx}', + './components/**/*.{js,ts,jsx,tsx,mdx}', + // `src`ディレクトリを使用している場合: + './src/**/*.{js,ts,jsx,tsx,mdx}', + ], + theme: { + extend: {}, + }, + plugins: [], +} +export default config +``` + + + + +```js title="tailwind.config.js" switcher +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + './app/**/*.{js,ts,jsx,tsx,mdx}', + './components/**/*.{js,ts,jsx,tsx,mdx}', + // `src`ディレクトリを使用している場合: + './src/**/*.{js,ts,jsx,tsx,mdx}', + ], + theme: { + extend: {}, + }, + plugins: [], +} +``` + + + + +`postcss.config.js`を変更する必要はありません。 + +### Tailwindの使用 {#using-tailwind} + +[グローバルスタイルシート](#global-css)に[Tailwindディレクティブ](https://tailwindcss.com/docs/functions-and-directives#directives)を追加します。例: + +```css title="app/globals.css" +@tailwind base; +@tailwind components; +@tailwind utilities; +``` + +次に、スタイルをroot レイアウトにインポートします: + + + + +```tsx title="app/layout.tsx" switcher +import type { Metadata } from 'next' + +// アプリケーションのすべてのルートにこれらのスタイルが適用されます +import './globals.css' + +export const metadata: Metadata = { + title: 'Create Next App', + description: 'Generated by create next app', +} + +export default function RootLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + + {children} + + ) +} +``` + + + + +```jsx title="app/layout.js" switcher +// アプリケーションのすべてのルートにこれらのスタイルが適用されます +import './globals.css' + +export const metadata = { + title: 'Create Next App', + description: 'Generated by create next app', +} + +export default function RootLayout({ children }) { + return ( + + {children} + + ) +} +``` + + + + +最後に、アプリケーション内でTailwindのユーティリティクラスを記述することができます。 + + + + +```tsx title="app/page.tsx" switcher +export default function Page() { + return

Hello, Next.js!

+} +``` + +
+ + +```jsx title="app/page.js" switcher +export default function Page() { + return

Hello, Next.js!

+} +``` + +
+
+ +## Sass {#sass} + +Next.jsは、[`.scss`](https://sass-lang.com/documentation/syntax/#scss)と[`.sass`](https://sass-lang.com/documentation/syntax#the-indented-syntax)の拡張子と構文を使用して[Sass](https://sass-lang.com/)と統合します。 + +コンポーネントレベルのSassは、`.module.scss`または`.module.sass`拡張子を使用して[CSS Modules](#css-modules)で使用することもできます。 + +### Sassのインストール {#installing-sass} + +Sassを使用開始するために、`sass`パッケージをインストールします: + +```bash title="Terminal" +npm install --save-dev sass +``` + +### Sassオプションのカスタマイズ {#customizing-sass-options} + +Sassオプションを設定したい場合は、`next.config.js`の`sassOptions`を使用します。 + + + + +```ts title="next.config.ts" switcher +import type { NextConfig } from 'next' + +const nextConfig: NextConfig = { + sassOptions: { + additionalData: `$var: red;`, + }, +} + +export default nextConfig +``` + + + + +```js title="next.config.js" switcher +/** @type {import('next').NextConfig} */ + +const nextConfig = { + sassOptions: { + additionalData: `$var: red;`, + }, +} + +module.exports = nextConfig +``` + + + + +`sassOptions`設定の詳細については、[APIリファレンス](/docs/app/api-reference/config/next-config-js/sassOptions)を参照してください。 + +## CSS-in-JS {#css-in-js} + +> **警告:** 実行時にJavaScriptを必要とするCSS-in-JSライブラリは、現在React Server Componentsではサポートされていません。CSS-in-JSを新しいReact機能と使用するには、ライブラリの作者がReactの最新バージョンをサポートする必要があります。 + +以下のライブラリは、`app`ディレクトリ内の**Client Components**でサポートされています(アルファベット順): + +- [`ant-design`](https://ant.design/docs/react/use-with-next#using-app-router) +- [`chakra-ui`](https://chakra-ui.com/getting-started/nextjs-app-guide) +- [`@fluentui/react-components`](https://react.fluentui.dev/?path=/docs/concepts-developer-server-side-rendering-next-js-appdir-setup--page) +- [`kuma-ui`](https://kuma-ui.com) +- [`@mui/material`](https://mui.com/material-ui/guides/next-js-app-router/) +- [`@mui/joy`](https://mui.com/joy-ui/integrations/next-js-app-router/) +- [`pandacss`](https://panda-css.com) +- [`styled-jsx`](#styled-jsx) +- [`styled-components`](#styled-components) +- [`stylex`](https://stylexjs.com) +- [`tamagui`](https://tamagui.dev/docs/guides/next-js#server-components) +- [`tss-react`](https://tss-react.dev/) +- [`vanilla-extract`](https://vanilla-extract.style) + +以下は現在サポートを進めています: + +- [`emotion`](https://github.com/emotion-js/emotion/issues/2928) + +Server Componentsをスタイリングしたい場合は、[CSS Modules](#css-modules)または[Tailwind CSS](#tailwind-css)のようにCSSファイルを出力する他のソリューションを使用することをお勧めします。 + +### CSS-in-JSの設定 {#configuring-css-in-js} + +CSS-in-JSを設定するには、以下が必要です: + +1. レンダリング時にすべてのCSSルールを収集する**スタイルレジストリ**を作成する; +2. それらを使用する可能性があるコンテンツの前にルールを注入するために`useServerInsertedHTML`フックを使用する; +3. Render時にアプリケーションをスタイルレジストリでラップするClient Componentを作成する; + +#### `styled-jsx` {#styled-jsx} + +アプリケーション用に`styled-jsx`を設定するには、新しいレジストリを作成します: + + + + +```tsx title="app/registry.tsx" switcher +'use client' + +import React, { useState } from 'react' +import { useServerInsertedHTML } from 'next/navigation' +import { StyleRegistry, createStyleRegistry } from 'styled-jsx' + +export default function StyledJsxRegistry({ + children, +}: { + children: React.ReactNode +}) { + // 遅延初期状態でスタイルシートを一度だけ作成する + // x-ref: https://reactjs.org/docs/hooks-reference.html#lazy-initial-state + const [jsxStyleRegistry] = useState(() => createStyleRegistry()) + + useServerInsertedHTML(() => { + const styles = jsxStyleRegistry.styles() + jsxStyleRegistry.flush() + return <>{styles} + }) + + return {children} +} +``` + + + + +```jsx title="app/registry.js" switcher +'use client' + +import React, { useState } from 'react' +import { useServerInsertedHTML } from 'next/navigation' +import { StyleRegistry, createStyleRegistry } from 'styled-jsx' + +export default function StyledJsxRegistry({ children }) { + // 遅延初期状態でスタイルシートを一度だけ作成する + // x-ref: https://reactjs.org/docs/hooks-reference.html#lazy-initial-state + const [jsxStyleRegistry] = useState(() => createStyleRegistry()) + + useServerInsertedHTML(() => { + const styles = jsxStyleRegistry.styles() + jsxStyleRegistry.flush() + return <>{styles} + }) + + return {children} +} +``` + + + + +次に、レジストリで[ルートレイアウト](/docs/app/api-reference/file-conventions/layout#root-layouts)をラップします: + + + + +```tsx title="app/layout.tsx" switcher +import StyledJsxRegistry from './registry' + +export default function RootLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + + + {children} + + + ) +} +``` + + + + +```jsx title="app/layout.js" switcher +import StyledJsxRegistry from './registry' + +export default function RootLayout({ children }) { + return ( + + + {children} + + + ) +} +``` + + + + +#### `styled-components` {#styled-components} + +`styled-components`を使用するには、`next.config.js`で有効にします: + + + + +```ts title="next.config.ts" switcher +import type { NextConfig } from 'next' + +const nextConfig: NextConfig = { + compiler: { + styledComponents: true, + }, +} + +export default nextConfig +``` + + + + +```js title="next.config.js" switcher +/** @type {import('next').NextConfig} */ +const nextConfig = { + compiler: { + styledComponents: true, + }, +} +``` + + + + +次に、`styled-components` APIを使用して、レンダリング中に生成されるすべてのCSSスタイルルールを収集するグローバルレジストリコンポーネントを作成し、それらのルールを返す関数を作成します。次に、`useServerInsertedHTML`フックを使用して、レジストリで収集されたスタイルをroot レイアウトの``タグに注入します。 + + + + +```tsx title="lib/registry.tsx" switcher +'use client' + +import React, { useState } from 'react' +import { useServerInsertedHTML } from 'next/navigation' +import { ServerStyleSheet, StyleSheetManager } from 'styled-components' + +export default function StyledComponentsRegistry({ + children, +}: { + children: React.ReactNode +}) { + // 遅延初期状態でスタイルシートを一度だけ作成する + // x-ref: https://reactjs.org/docs/hooks-reference.html#lazy-initial-state + const [styledComponentsStyleSheet] = useState(() => new ServerStyleSheet()) + + useServerInsertedHTML(() => { + const styles = styledComponentsStyleSheet.getStyleElement() + styledComponentsStyleSheet.instance.clearTag() + return <>{styles} + }) + + if (typeof window !== 'undefined') return <>{children} + + return ( + + {children} + + ) +} +``` + + + + +```jsx title="lib/registry.js" switcher +'use client' + +import React, { useState } from 'react' +import { useServerInsertedHTML } from 'next/navigation' +import { ServerStyleSheet, StyleSheetManager } from 'styled-components' + +export default function StyledComponentsRegistry({ children }) { + // 遅延初期状態でスタイルシートを一度だけ作成する + // x-ref: https://reactjs.org/docs/hooks-reference.html#lazy-initial-state + const [styledComponentsStyleSheet] = useState(() => new ServerStyleSheet()) + + useServerInsertedHTML(() => { + const styles = styledComponentsStyleSheet.getStyleElement() + styledComponentsStyleSheet.instance.clearTag() + return <>{styles} + }) + + if (typeof window !== 'undefined') return <>{children} + + return ( + + {children} + + ) +} +``` + + + + +root レイアウトの`children`をスタイルレジストリコンポーネントでラップします: + + + + +```tsx title="app/layout.tsx" switcher +import StyledComponentsRegistry from './lib/registry' + +export default function RootLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + + + {children} + + + ) +} +``` + + + + +```jsx title="app/layout.js" switcher +import StyledComponentsRegistry from './lib/registry' + +export default function RootLayout({ children }) { + return ( + + + {children} + + + ) +} +``` + + + + +## 外部スタイルシート {#external-stylesheets} + +外部パッケージで公開されたスタイルシートは、`app`ディレクトリ内のどこにでもインポートできます。コンポーネントにコロケートしている場合も同様です: + + + + +```tsx title="app/layout.tsx" switcher +import 'bootstrap/dist/css/bootstrap.css' + +export default function RootLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + + {children} + + ) +} +``` + + + + +```jsx title="app/layout.js" switcher +import 'bootstrap/dist/css/bootstrap.css' + +export default function RootLayout({ children }) { + return ( + + {children} + + ) +} +``` + + + + +外部スタイルシートは、npmパッケージから直接インポートするか、コードベースにコロケートしてダウンロードする必要があります。``を使用することはできません。 diff --git a/docs/01-app/01-getting-started/06-data-fetching-and-streaming.mdx b/docs/01-app/01-getting-started/06-data-fetching-and-streaming.mdx new file mode 100644 index 0000000..5299c8d --- /dev/null +++ b/docs/01-app/01-getting-started/06-data-fetching-and-streaming.mdx @@ -0,0 +1,402 @@ +--- +title: 'データを取得しストリーミングする方法' +nav_title: 'データ取得とストリーミング' +description: 'Next.jsアプリケーションでデータの取得とコンテンツのストリーミング方法を学びます。' +related: + links: + - 'app/api-reference/functions/fetch' + - 'app/api-reference/file-conventions/loading' +--- + +このページでは、[server component](#server-components) および [client component](#client-components) でデータを取得する方法、そしてデータに依存するコンテンツを [ストリーミング](#streaming) する方法を説明します。 + +## データの取得 {#fetching-data} + +### server component {#server-components} + +server component では、次の方法でデータを取得できます: + +1. [`fetch` API](#with-the-fetch-api) を使用する +2. [ORMまたはデータベース](#with-an-orm-or-database) を使用する + +#### `fetch` API を使用して {#with-the-fetch-api} + +`fetch` API を使ってデータを取得するには、コンポーネントを非同期関数に変換し、`fetch` を待ちます。例えば: + + + + +```tsx title="app/blog/page.tsx" switcher +export default async function Page() { + const data = await fetch('https://api.vercel.app/blog') + const posts = await data.json() + return ( +
    + {posts.map((post) => ( +
  • {post.title}
  • + ))} +
+ ) +} +``` + +
+ + +```jsx title="app/blog/page.js" switcher +export default async function Page() { + const data = await fetch('https://api.vercel.app/blog') + const posts = await data.json() + return ( +
    + {posts.map((post) => ( +
  • {post.title}
  • + ))} +
+ ) +} +``` + +
+
+ +#### ORMまたはデータベースを使用して {#with-an-orm-or-database} + +ORM またはデータベースを使ってデータを取得するには、コンポーネントを非同期関数に変換し、呼び出しを待ちます: + + + + +```tsx title="app/blog/page.tsx" switcher +import { db, posts } from '@/lib/db' + +export default async function Page() { + const allPosts = await db.select().from(posts) + return ( +
    + {allPosts.map((post) => ( +
  • {post.title}
  • + ))} +
+ ) +} +``` + +
+ + +```jsx title="app/blog/page.js" switcher +import { db, posts } from '@/lib/db' + +export default async function Page() { + const allPosts = await db.select().from(posts) + return ( +
    + {allPosts.map((post) => ( +
  • {post.title}
  • + ))} +
+ ) +} +``` + +
+
+ +### client component {#client-components} + +React の [`use` フック](https://react.dev/reference/react/use) を使用して、サーバーからクライアントにデータを [ストリーミング](#streaming) できます。まず server component でデータを取得し、そのプロミスを client component に props として渡します: + + + + +```tsx title="app/blog/page.tsx" switcher +import Posts from '@/app/ui/posts' +import { Suspense } from 'react' + +export default function Page() { + // データ取得関数を待機しません + const posts = getPosts() + + return ( + Loading...}> + + + ) +} +``` + + + + +```jsx title="app/blog/page.js" switcher +import Posts from '@/app/ui/posts' +import { Suspense } from 'react' + +export default function Page() { + // データ取得関数を待機しません + const posts = getPosts() + + return ( + Loading...}> + + + ) +} +``` + + + + +次に、client component で `use` フックを使ってプロミスを読み込みます: + + + + +```tsx title="app/ui/posts.tsx" switcher +'use client' +import { use } from 'react' + +export default function Posts({ posts }) { + const posts = use(posts) + + return ( +
    + {posts.map((post) => ( +
  • {post.title}
  • + ))} +
+ ) +} +``` + +
+ + +```jsx title="app/ui/posts.js" switcher +'use client' +import { use } from 'react' + +export default function Posts({ posts }) { + const posts = use(posts) + + return ( +
    + {posts.map((post) => ( +
  • {post.title}
  • + ))} +
+ ) +} +``` + +
+
+ +上の例では、`` コンポーネントを [`` バウンダリ](https://react.dev/reference/react/Suspense) 内でラップする必要があります。これは、プロミスが解決される間、フォールバックが表示されることを意味します。[ストリーミング](#streaming) についてさらに学んでください。 + +また、[SWR](https://swr.vercel.app/) や [React Query](https://tanstack.com/query/latest) などのコミュニティライブラリを使用することもできます。これらのライブラリは、キャッシング、ストリーミング、およびその他の機能に関する独自のセマンティクスを持っています。例えば: + + + + +```tsx title="app/blog/page.tsx" switcher +'use client' +import useSWR from 'swr' + +const fetcher = (url) => fetch(url).then((r) => r.json()) + +export default function BlogPage() { + const { data, error, isLoading } = useSWR( + 'https://api.vercel.app/blog', + fetcher + ) + + if (isLoading) return
Loading...
+ if (error) return
Error: {error.message}
+ + return ( +
    + {data.map((post: { id: string; title: string }) => ( +
  • {post.title}
  • + ))} +
+ ) +} +``` + +
+ + +```jsx title="app/blog/page.js" switcher +'use client' +import useSWR from 'swr' + +const fetcher = (url) => fetch(url).then((r) => r.json()) + +export default function BlogPage() { + const { data, error, isLoading } = useSWR( + 'https://api.vercel.app/blog', + fetcher + ) + + if (isLoading) return
Loading...
+ if (error) return
Error: {error.message}
+ + return ( +
    + {data.map((post) => ( +
  • {post.title}
  • + ))} +
+ ) +} +``` + +
+
+ +## ストリーミング {#streaming} + +> **警告:** 以下の内容は、[`dynamicIO` 設定オプション](/docs/app/api-reference/config/next-config-js/dynamicIO) が有効であることを前提としています。このフラグは Next.js 15 canary で導入されました。 + +server component において `async/await` を使用すると、Next.js は **動的レンダリング** に切り替わります。これは、すべてのユーザーリクエストに対してサーバーでデータが取得され、レンダリングされることを意味します。もし遅いデータリクエストがあれば、ルート全体のレンダリングがブロックされます。 + +初期読み込み時間とユーザー体験を向上させるために、ページの HTML をより小さなチャンクに分割し、チャンクをサーバーからクライアントに順次送信するストリーミングを使用できます。 + +ストリーミングを使用したサーバーレンダリングの仕組み + +アプリケーションでストリーミングを実装する方法は2つあります: + +1. [`loading.js` ファイル](#with-loading-js) を使用する +2. React の [`` コンポーネント](#with-suspense) を使用する + +### `loading.js` を使用して {#with-loading-js} + +ページと同じフォルダに `loading.js` ファイルを作成することで、データ取得中に**ページ全体**をストリームできます。`app/blog/page.js` をストリーミングするには、`app/blog` フォルダにこのファイルを追加します。 + +loading.jsファイルを含むブログフォルダ構成 + + + + +```tsx title="app/blog/loading.tsx" switcher +export default function Loading() { + // ローディングUIをここで定義します + return
Loading...
+} +``` + +
+ + +```jsx title="app/blog/loading.js" switcher +export default function Loading() { + // ローディングUIをここで定義します + return
Loading...
+} +``` + +
+
+ +ナビゲーション時に、ユーザーはページがレンダリングされるまでレイアウトと[ローディング状態](#creating-meaningful-loading-states) を即座に確認します。レンダリングが完了すると新しいコンテンツが自動的に入れ替わります。 + +ローディングUI + +バックグラウンドで、`loading.js` は `layout.js` 内にネストされ、`page.js` ファイルと配下のすべての子を自動的に `` バウンダリでラップします。 + +loading.jsの概要 + +このアプローチはルートセグメント(レイアウトおよびページ)に適していますが、よりきめ細かなストリーミングには `` を使用できます。 + +### `` を使用して {#with-suspense} + +`` を使用すると、ページのどの部分をストリーム化するかをよりきめ細かく指定できます。例えば、`` バウンダリの外にあるページ内容を即座に表示し、そのバウンダリ内にあるブログ記事のリストをストリームできます。 + + + + +```tsx title="app/blog/page.tsx" switcher +import { Suspense } from 'react' +import BlogList from '@/components/BlogList' +import BlogListSkeleton from '@/components/BlogListSkeleton' + +export default function BlogPage() { + return ( +
+ {/* この内容は即座にクライアントに送信されます */} +
+

Welcome to the Blog

+

Read the latest posts below.

+
+
+ {/* バウンダリでラップされたコンテンツはストリームされます */} + }> + + +
+
+ ) +} +``` + +
+ + +```jsx title="app/blog/page.js" switcher +import { Suspense } from 'react' +import BlogList from '@/components/BlogList' +import BlogListSkeleton from '@/components/BlogListSkeleton' + +export default function BlogPage() { + return ( +
+ {/* この内容は即座にクライアントに送信されます */} +
+

Welcome to the Blog

+

Read the latest posts below.

+
+
+ {/* バウンダリでラップされたコンテンツはストリームされます */} + }> + + +
+
+ ) +} +``` + +
+
+ +### 意味のあるローディング状態を作成する {#creating-meaningful-loading-states} + +インスタント・ローディング状態は、ナビゲーションの後にユーザーにすぐに表示されるフォールバックUIです。最良のユーザー体験を提供するために、ローディング状態は意味のあるものであり、アプリケーションが反応していることをユーザーに理解してもらえるようにすることをお勧めします。例えば、スケルトンやスピナー、または将来の画面の小さくても意味のある部分(カバー写真やタイトルなど)を使用することができます。 + +開発中は、[React Devtools](https://react.dev/learn/react-developer-tools) を使ってコンポーネントのローディング状態をプレビューおよび検査することができます。 diff --git a/docs/01-app/02-building-your-application/01-routing/04-linking-and-navigating.mdx b/docs/01-app/02-building-your-application/01-routing/04-linking-and-navigating.mdx index 795afc3..562cfb9 100644 --- a/docs/01-app/02-building-your-application/01-routing/04-linking-and-navigating.mdx +++ b/docs/01-app/02-building-your-application/01-routing/04-linking-and-navigating.mdx @@ -1,26 +1,26 @@ --- title: 'リンクとナビゲーション' -description: 'Next.jsにおけるナビゲーションの仕組みと、LinkコンポーネントとuseRouterフックの使用方法を学びます' +description: 'Next.jsでのナビゲーションの仕組みと、Linkコンポーネントや`useRouter`フックの使い方を学びましょう。' related: links: - 'app/building-your-application/caching' - 'app/api-reference/config/typescript' --- -Next.jsでは、ルート間をナビゲートする方法は4つあります: +Next.jsでは、ルート間を移動する方法が4つあります: -- [`` コンポーネント](#link-component)を使用する -- [`useRouter` フック](#userouter-hook)を使用する([Client Components](/docs/app/building-your-application/rendering/client-components)) -- [`redirect` 関数](#redirect-function)を使用する([Server Components](/docs/app/building-your-application/rendering/server-components)) -- ネイティブな[History API](#using-the-native-history-api)を使用する +- [`` コンポーネント](#link-component)を使う +- [`useRouter` フック](#userouter-hook)を使う([Client Components](/docs/app/building-your-application/rendering/client-components)) +- [`redirect` 関数](#redirect-function)を使う([Server Components](/docs/app/building-your-application/rendering/server-components)) +- ネイティブの[History API](#using-the-native-history-api)を使う -このページでは、それぞれのオプションの使用方法について説明し、ナビゲーションの仕組みを詳しく見ていきます。 +このページでは、これらの各オプションの使い方を説明し、ナビゲーションの仕組みを詳しく見ていきます。 ## `` コンポーネント {#link-component} -``は、HTMLの`
`タグを拡張し、[プリフェッチ](#2-prefetching)とクライアントサイドでのルート間ナビゲーションを提供する組み込みのコンポーネントです。Next.jsでルート間をナビゲートする主な推奨方法です。 +``は、[プリフェッチ](#2-prefetching)や、ルート間のクライアントサイドでのナビゲーションを提供するためにHTMLの``タグを拡張した組み込みコンポーネントです。Next.jsでルート間をナビゲートする際の主要で推奨される方法です。 -`next/link`からインポートし、`href`プロップをコンポーネントに渡すことで使用できます: +`next/link`からインポートし、`href`プロパティとしてルートを``コンポーネントに渡して使用します: @@ -47,11 +47,11 @@ export default function Page() { -``に渡す他のオプションの`props`もあります。詳細は[APIリファレンス](/docs/app/api-reference/components/link)をご覧ください。 +その他のオプションのpropsは、[``コンポーネントのAPIリファレンス](/docs/app/api-reference/components/link)を参照してください。 ## `useRouter()` フック {#userouter-hook} -`useRouter`フックを使うと、[Client Components](/docs/app/building-your-application/rendering/client-components)からプログラム的にルートを変更できます。 +`useRouter`フックは、[Client Components](/docs/app/building-your-application/rendering/client-components)からプログラム的にルートを変更することを可能にします。 ```jsx title="app/page.js" 'use client' @@ -69,13 +69,13 @@ export default function Page() { } ``` -`useRouter`メソッドの完全なリストについては、[APIリファレンス](/docs/app/api-reference/functions/use-router)を参照してください。 +`useRouter`のメソッドの完全なリストは、[APIリファレンス](/docs/app/api-reference/functions/use-router)を参照してください。 -> **推奨事項:** 特定の要件がない限り、ルート間をナビゲートするためには``コンポーネントを使用してください。 +> **推奨:** 特定の要件がない限り、ルート間のナビゲーションには``コンポーネントを使用してください。 ## `redirect` 関数 {#redirect-function} -[Server Components](/docs/app/building-your-application/rendering/server-components)の場合、代わりに`redirect`関数を使用してください。 +[Server Components](/docs/app/building-your-application/rendering/server-components)では、代わりに`redirect`関数を使用します。 @@ -89,12 +89,21 @@ async function fetchTeam(id: string) { return res.json() } -export default async function Profile({ params }: { params: { id: string } }) { - const team = await fetchTeam(params.id) - if (!team) { +export default async function Profile({ + params, +}: { + params: Promise<{ id: string }> +}) { + const id = (await params).id + if (!id) { redirect('/login') } + const team = await fetchTeam(id) + if (!team) { + redirect('/join') + } + // ... } ``` @@ -112,11 +121,16 @@ async function fetchTeam(id) { } export default async function Profile({ params }) { - const team = await fetchTeam(params.id) - if (!team) { + const id = (await params).id + if (!id) { redirect('/login') } + const team = await fetchTeam(id) + if (!team) { + redirect('/join') + } + // ... } ``` @@ -124,25 +138,25 @@ export default async function Profile({ params }) { -> **知っておいてよい点**: +> **知っておくとよいこと**: > -> - `redirect`はデフォルトで307(Temporary Redirect)ステータスコードを返します。サーバーアクションで使用した場合、303(See Other)を返します。これは、POSTリクエストの結果として成功ページにリダイレクトする際によく使用されます。 -> - `redirect`は内部的にエラーを投げるので、`try/catch`ブロックの外で呼び出されるべきです。 -> - `redirect`はクライアントコンポーネントでのレンダリングプロセス中に呼び出せますが、イベントハンドラ内では使用できません。代わりに[`useRouter`フック](#userouter-hook)を使用できます。 -> - `redirect`は絶対URLも受け入れ、外部リンクにリダイレクトするために使用できます。 -> - レンダープロセスの前にリダイレクトしたい場合は、[`next.config.js`](/docs/app/building-your-application/routing/redirecting#redirects-in-nextconfigjs)や[ミドルウェア](/docs/app/building-your-application/routing/redirecting#nextresponseredirect-in-middleware)を使用してください。 +> - デフォルトで、`redirect`は307(Temporary Redirect)ステータスコードを返します。Server Actionで使用すると、303(See Other)が返されます。これはPOSTリクエストの結果として、成功ページにリダイレクトする際に一般的に使用されます。 +> - `redirect`は内部でエラーをスローするため、`try/catch`ブロックの外で呼び出す必要があります。 +> - `redirect`は、Client Components内でレンダリングプロセス中に呼び出すことができますが、イベントハンドラーでは呼び出せません。代わりに[`useRouter`フック](#userouter-hook)を使用できます。 +> - `redirect`は絶対URLも受け入れ、外部リンクへのリダイレクトに使用できます。 +> - レンダリングプロセスの前にリダイレクトしたい場合は、[`next.config.js`](/docs/app/building-your-application/routing/redirecting#redirects-in-nextconfigjs)や[ミドルウェア](/docs/app/building-your-application/routing/redirecting#nextresponseredirect-in-middleware)を使用します。 -より詳しい情報は、[`redirect` APIリファレンス](/docs/app/api-reference/functions/redirect)を参照してください。 +詳しくは[`redirect` APIリファレンス](/docs/app/api-reference/functions/redirect)を参照してください。 -## ネイティブなHistory APIを使用する {#using-the-native-history-api} +## ネイティブのHistory APIを使う {#using-the-native-history-api} -Next.jsでは、ネイティブの[`window.history.pushState`](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState)と[`window.history.replaceState`](https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState)メソッドを使用して、ページをリロードせずにブラウザの履歴スタックを更新することができます。 +Next.jsでは、ネイティブの[`window.history.pushState`](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState)と[`window.history.replaceState`](https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState)メソッドを使用して、ページを再読み込みせずにブラウザの履歴スタックを更新することができます。 -`pushState`と`replaceState`の呼び出しはNext.js Routerと統合され、[`usePathname`](/docs/app/api-reference/functions/use-pathname)と[`useSearchParams`](/docs/app/api-reference/functions/use-search-params)と同期できます。 +`pushState`と`replaceState`の呼び出しは、Next.js Routerに統合され、[`usePathname`](/docs/app/api-reference/functions/use-pathname)や[`useSearchParams`](/docs/app/api-reference/functions/use-search-params)と同期することができます。 ### `window.history.pushState` {#window-history-pushstate} -ブラウザの履歴スタックに新しいエントリを追加するために使用します。ユーザーは前の状態に戻ることができます。例えば、製品リストをソートするには: +ブラウザの履歴スタックに新しいエントリを追加するのに使用します。ユーザーは前の状態に戻ることができます。たとえば、商品のリストをソートするには: @@ -201,7 +215,7 @@ export default function SortProducts() { ### `window.history.replaceState` {#window-history-replacestate} -ブラウザの履歴スタックの現在のエントリを置き換えるために使用します。ユーザーは前の状態に戻ることができません。例えば、アプリケーションのロケールを切り替えるには: +ブラウザの履歴スタックにおける現在のエントリを置き換えるのに使用します。ユーザーは前の状態に戻ることはできません。たとえば、アプリケーションのロケールを切り替えるには: @@ -260,67 +274,65 @@ export function LocaleSwitcher() { ## ルーティングとナビゲーションの仕組み {#how-routing-and-navigation-works} -App Routerは、ルーティングとナビゲーションにハイブリッドアプローチを採用しています。サーバー上では、アプリケーションコードがルートセグメントによって自動的に[コード分割](#1-code-splitting)され、クライアント側では、Next.jsがルートセグメントを[プリフェッチ](#2-prefetching)し[キャッシュ](#3-caching)します。つまり、ユーザーが新しいルートに移動しても、ブラウザはページをリロードせず、変更されたルートセグメントだけが再レンダリングされます。これにより、ナビゲーション体験とパフォーマンスが向上します。 +App Routerは、ハイブリッドアプローチでルーティングとナビゲーションを行います。サーバー上でアプリケーションコードは自動的にルートセグメントごとに[コードスプリット](#1-code-splitting)されます。そして、クライアント側では、Next.jsがルートセグメントを[プリフェッチ](#2-prefetching)し、[キャッシュ](#3-caching)します。これにより、ユーザーが新しいルートに移動した際、ブラウザがページをリロードせず、変化するルートセグメントのみが再レンダリングされるため、ナビゲーションの体験とパフォーマンスが向上します。 -### 1. コード分割 {#1-code-splitting} +### 1. コードスプリッティング {#1-code-splitting} -コード分割により、アプリケーションコードを小さなバンドルに分割し、ブラウザでダウンロードおよび実行できるようになります。これにより、データ転送量と各リクエストの実行時間が短縮され、パフォーマンスが向上します。 +コードスプリッティングにより、アプリケーションコードが小さなバンドルに分割され、ブラウザによってダウンロードおよび実行されるようになります。これにより、データ転送量と各リクエストの実行時間が削減され、パフォーマンスが向上します。 -[Server Components](/docs/app/building-your-application/rendering/server-components)により、アプリケーションコードはルートセグメントによって自動的にコード分割されます。これにより、ナビゲーション時には現在のルートに必要なコードのみが読み込まれます。 +[Server Components](/docs/app/building-your-application/rendering/server-components)は、アプリケーションコードをルートセグメントごとに自動的にコードスプリットすることができます。これにより、ナビゲーション時に現在のルートに必要なコードのみがロードされます。 ### 2. プリフェッチ {#2-prefetching} -プリフェッチは、ユーザーが訪問する前にバックグラウンドでルートを事前にロードする方法です。 +プリフェッチとは、ユーザーが訪れる前にバックグラウンドでルートを事前に読み込む方法です。 -Next.jsではルートがプリフェッチされる方法は2つあります: +Next.jsでは、ルートをプリフェッチする方法が2つあります: -- **`` コンポーネント**:ユーザーのビューポートに表示されると、ルートは自動的にプリフェッチされます。プリフェッチは、ページが最初にロードされるときや、スクロールによってビューに入るときに行われます。 -- **`router.prefetch()`**:`useRouter`フックを使用して、プログラム的にルートをプリフェッチできます。 +- **`` コンポーネント**:ルートはユーザーのビューポート内で可視化されると自動的にプリフェッチされます。プリフェッチはページが初めてロードされたときやスクロールによってビューに入るときに発生します。 +- **`router.prefetch()`**:`useRouter`フックを使用してルートをプログラム的にプリフェッチすることができます。 -``のデフォルトのプリフェッチ動作(つまり、`prefetch`プロップが未指定または`null`に設定されている場合)は、[`loading.js`](/docs/app/api-reference/file-conventions/loading)の使用に応じて異なります。共有レイアウトのみがプリフェッチされ、「コンポーネントのツリー」がレンダリングされる最初の`loading.js`ファイルまでキャッシュされます。これにより、動的ルート全体をフェッチするコストが削減され、即時の[ローディング状態](/docs/app/building-your-application/routing/loading-ui-and-streaming#instant-loading-states)がユーザーにより良い視覚的フィードバックを提供します。 +``のデフォルトのプリフェッチ動作(`prefetch` propが未指定または`null`に設定されている場合)は、使用している[`loading.js`](/docs/app/api-reference/file-conventions/loading)によって異なります。レンダリングされたコンポーネントの"tree"に沿って最初の`loading.js`ファイルまでの共有レイアウトのみが`30s`間プリフェッチされ、キャッシュされます。これにより、動的ルート全体をフェッチするコストが削減され、ユーザーに対する視覚的フィードバックを改善するための[即時ローディング状態](/docs/app/building-your-application/routing/loading-ui-and-streaming#instant-loading-states)を表示することができます。 -プリフェッチを無効にするには、`prefetch`プロップを`false`に設定します。あるいは、`prefetch`プロップを`true`に設定して、ローディングの境界を超えて完全なページデータをプリフェッチすることができます。 +`prefetch`プロパティを`false`に設定することで、プリフェッチを無効にできます。また、`prefetch`プロパティを`true`に設定することにより、ローディングの境界を超えた完全なページデータをプリフェッチできます。 -詳細は[`` APIリファレンス](/docs/app/api-reference/components/link)を参照してください。 +詳細は[``APIリファレンス](/docs/app/api-reference/components/link)を参照してください。 -> **知っておいてよい点**: +> **知っておくとよいこと**: > -> - プリフェッチは開発環境では有効ではなく、本番環境でのみ有効です。 +> - プリフェッチは開発環境では有効になっておらず、本番環境でのみ有効です。 -### 3. キャッシュ {#3-caching} +### 3. キャッシング {#3-caching} -Next.jsには**インメモリーのクライアントサイドキャッシュ**があり、[Router Cache](/docs/app/building-your-application/caching#client-side-router-cache)と呼ばれます。ユーザーがアプリをナビゲートすると、[プリフェッチされた](#2-prefetching)ルートセグメントと訪問したルートのReactサーバーコンポーネントペイロードがキャッシュに保存されます。 +Next.jsには、**インメモリのクライアントサイドキャッシュ**として[Router Cache](/docs/app/building-your-application/caching#client-side-router-cache)があります。ユーザーがアプリケーション内をナビゲートする際、[プリフェッチされた](#2-prefetching)ルートセグメントや訪問済みルートのReact Server Component Payloadがキャッシュに保存されます。 -つまり、ナビゲーション時には、可能な限りキャッシュが再利用され、新たなサーバーへのリクエストを行う代わりに、キャッシュが使用されます。これにより、リクエスト数とデータ転送量が削減され、パフォーマンスが向上します。 +これにより、ナビゲーション時にキャッシュができるだけ再利用され、サーバーへの新しいリクエストが発生しません。これにより、リクエスト数とデータ転送量が減少し、パフォーマンスが向上します。 -[Router Cache](/docs/app/building-your-application/caching#client-side-router-cache)の仕組みと構成方法についての詳細をご覧ください。 +[Router Cache](/docs/app/building-your-application/caching#client-side-router-cache)の動作および設定方法の詳細については、こちらを参照してください。 -### 4. 部分的なレンダリング {#4-partial-rendering} +### 4. 部分レンダリング {#4-partial-rendering} -部分的なレンダリングとは、クライアント上のナビゲーションで変更されるルートセグメントのみが再レンダリングされ、共有セグメントは保持されることを意味します。 +部分レンダリングとは、ナビゲーション時に変化するルートセグメントのみがクライアントで再レンダリングされ、共有セグメントは保持されることを意味します。 -たとえば、2つの兄弟ルート`/dashboard/settings`と`/dashboard/analytics`間を移動する際には、`settings`ページがアンマウントされ、`analytics`ページが新しい状態でマウントされ、共有の`dashboard`レイアウトが保存されます。この動作は、同じ動的セグメント上の2つのルート間でも発生します。たとえば、`/blog/[slug]/page`および`/blog/first`から`/blog/second`へのナビゲーション時です。 +たとえば、2つの兄弟ルートである`/dashboard/settings`と`/dashboard/analytics`間を移動すると、`settings`ページがアンマウントされ、`analytics`ページが新しい状態でマウントされ、共有されている`dashboard`レイアウトは保持されます。この動作は、`/blog/[slug]/page`で同じ動的セグメントに対して、`/blog/first`から`/blog/second`へ移動する際にも見られます。 部分的なレンダリングの仕組み -部分的なレンダリングがない場合、各ナビゲーションはクライアントですべてのページを再レンダリングさせます。変更されるセグメントのみをレンダリングすることで、データ転送量と実行時間が削減され、パフォーマンスが向上します。 +部分レンダリングがない場合、ナビゲーションのたびにクライアントでページ全体が再レンダリングされます。変化したセグメントをレンダリングすることで転送データ量と実行時間が削減され、パフォーマンスが向上します。 ### 5. ソフトナビゲーション {#5-soft-navigation} -ブラウザはページ間のナビゲーションで「ハードナビゲーション」を行います。Next.jsのApp Routerは、ページ間での「ソフトナビゲーション」を可能にし、変更されたルートセグメントのみが再レンダリングされるようにします(部分的なレンダリング)。これにより、クライアントのReact stateがナビゲーション中に保存されます。 - -### 6. 前後のナビゲーション {#6-back-and-forward-navigation} +通常、ブラウザはページ間のナビゲーション時に「ハードナビゲーション」を行います。Next.jsのApp Routerは、「ソフトナビゲーション」を可能にし、変更されたルートセグメントのみが再レンダリングされる(部分レンダリング)ようにします。これにより、ナビゲーション中にクライアントのReact状態を保持できます。 -デフォルトでは、Next.jsは前後のナビゲーションでスクロール位置を維持し、[Router Cache](/docs/app/building-your-application/caching#client-side-router-cache)のルートセグメントを再利用します。 +### 6. 戻る・進むナビゲーション {#6-back-and-forward-navigation} -### 7. `pages/`と`app/`間のルーティング {#7-routing-between-pages-and-app} +デフォルトでは、Next.jsは戻る・進むナビゲーションに対してスクロール位置を維持し、[Router Cache](/docs/app/building-your-application/caching#client-side-router-cache)のルートセグメントを再利用します。 -`pages/`から`app/`へのインクリメンタル移行時に、Next.jsルーターは両者間のハードナビゲーションを自動的に処理します。`pages/`から`app/`への移行を検出するために、アプリルートの確率的チェックを活用したクライアントルーターフィルターがありますが、これは稀に偽陽性を引き起こす可能性があります。通常、こうした事例は非常に稀ですが、偽陽性の確率は0.01%に設定されています。この確率は、`next.config.js`の`experimental.clientRouterFilterAllowedRate`オプションを通じてカスタマイズできます。偽陽性率を下げると、クライアントバンドル内の生成されたフィルターのサイズが増加することに注意してください。 +### 7. `pages/` と `app/` 間のルーティング {#7-routing-between-pages-and-app} -完全にこの処理を無効にして、`pages/`と`app/`間のルーティングを手動で管理したい場合は、`next.config.js`で`experimental.clientRouterFilter`を`false`に設定できます。この機能が無効化されると、appルートと重なるページの動的ルートがデフォルトでは正しくナビゲートされません。 +`pages/`から`app/`へ段階的に移行する場合、Next.js routerは自動的に2つの間でハードナビゲーションを処理します。`pages/`から`app/`への移行を検出するために、App Routerは`probabilistic checking`を活用するクライアントルーターフィルターを使用します。このチェックにより、時折の誤検出が発生する可能性があります。デフォルトでは、そのような事象が発生する確率は非常に低く(0.01%)設定されています。この確率は、`next.config.js`の`experimental.clientRouterFilterAllowedRate`オプションでカスタマイズできます。この機能を完全に無効にし、`pages/`と`app/`間のルーティングを手動で管理したい場合、`next.config.js`で`experimental.clientRouterFilter`をfalseに設定できます。この機能を無効にすると、`pages`内の動的ルートが`app`のルートと重なった場合、デフォルトで適切にナビゲートできません。 diff --git a/docs/01-app/02-building-your-application/01-routing/07-redirecting.mdx b/docs/01-app/02-building-your-application/01-routing/07-redirecting.mdx index 8fe8461..a65c66e 100644 --- a/docs/01-app/02-building-your-application/01-routing/07-redirecting.mdx +++ b/docs/01-app/02-building-your-application/01-routing/07-redirecting.mdx @@ -1,6 +1,6 @@ --- title: 'リダイレクト' -description: 'Next.jsでリダイレクトを処理するさまざまな方法を学びます。' +description: 'Next.jsでリダイレクトを処理するさまざまな方法を学びましょう。' related: links: - 'app/api-reference/functions/redirect' @@ -9,27 +9,27 @@ related: - 'app/api-reference/config/next-config-js/redirects' --- -Next.jsでリダイレクトを処理する方法はいくつかあります。このページでは、利用可能な各オプション、ユースケース、および大量のリダイレクトを管理する方法について説明します。 +Next.jsでリダイレクトを処理する方法はいくつかあります。このページでは、それぞれの利用可能なオプション、使用例、および大量のリダイレクトの管理方法について説明します。 -| API | 目的 | 使用場所 | ステータスコード | -| -------------------------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------- | ----------------------------------- | -| [`redirect`](#redirect-function) | ミューテーションまたはイベント後にユーザーをリダイレクトする | Server Components、Server Actions、Route Handlers | 307(仮)または303(Server Action) | -| [`permanentRedirect`](#permanentredirect-function) | ミューテーションまたはイベント後にユーザーをリダイレクトする | Server Components、Server Actions、Route Handlers | 308(永続) | -| [`useRouter`](#userouter-hook) | クライアントサイドのナビゲーションを実行する | Client Componentsのイベントハンドラーで | 該当なし | -| [`next.config.js`内の`redirects`](#redirects-in-nextconfigjs) | パスに基づいて受信リクエストをリダイレクトする | `next.config.js`ファイル | 307(仮)または308(永続) | -| [`NextResponse.redirect`](#nextresponseredirect-in-middleware) | 条件に基づいて受信リクエストをリダイレクトする | ミドルウェア | 任意 | +| API | 目的 | 実行場所 | ステータスコード | +| -------------------------------------------------------------- | ---------------------------------------------------- | ------------------------------------------------- | --------------------------------------- | +| [`redirect`](#redirect-function) | 変更やイベント後にユーザーをリダイレクトする | Server Components, Server Actions, Route Handlers | 307 (一時的) または 303 (Server Action) | +| [`permanentRedirect`](#permanentredirect-function) | 変更やイベント後にユーザーをリダイレクトする | Server Components, Server Actions, Route Handlers | 308 (永久) | +| [`useRouter`](#userouter-hook) | クライアントサイドのナビゲーションを実行する | Event Handlers in Client Components | N/A | +| [`redirects` in `next.config.js`](#redirects-in-nextconfigjs) | パスに基づいてリクエストをリダイレクトする | `next.config.js` ファイル | 307 (一時的) または 308 (永久) | +| [`NextResponse.redirect`](#nextresponseredirect-in-middleware) | 条件に基づいてリクエストをリダイレクトする 優 先順位 | Middleware | 任意 | -| API | 目的 | 使用場所 | ステータスコード | -| -------------------------------------------------------------- | ---------------------------------------------- | ------------------------ | -------------------------- | -| [`useRouter`](#userouter-hook) | クライアントサイドのナビゲーションを実行する | コンポーネント | 該当なし | -| [`next.config.js`内の`redirects`](#redirects-in-nextconfigjs) | パスに基づいて受信リクエストをリダイレクトする | `next.config.js`ファイル | 307(仮)または308(永続) | -| [`NextResponse.redirect`](#nextresponseredirect-in-middleware) | 条件に基づいて受信リクエストをリダイレクトする | ミドルウェア | 任意 | +| API | 目的 | 実行場所 | ステータスコード | +| -------------------------------------------------------------- | -------------------------------------------- | ------------------------- | ------------------------------ | +| [`useRouter`](#userouter-hook) | クライアントサイドのナビゲーションを実行する | Components | N/A | +| [`redirects` in `next.config.js`](#redirects-in-nextconfigjs) | パスに基づいてリクエストをリダイレクトする | `next.config.js` ファイル | 307 (一時的) または 308 (永久) | +| [`NextResponse.redirect`](#nextresponseredirect-in-middleware) | 条件に基づいてリクエストをリダイレクトする | Middleware | 任意 | @@ -37,14 +37,14 @@ Next.jsでリダイレクトを処理する方法はいくつかあります。 ## `redirect` 関数 {#redirect-function} -`redirect` 関数を使用すると、ユーザーを別のURLにリダイレクトすることができます。`redirect`を[Server Components](/docs/app/building-your-application/rendering/server-components)、[Route Handlers](/docs/app/building-your-application/routing/route-handlers)、および[Server Actions](/docs/app/building-your-application/data-fetching/server-actions-and-mutations)で呼び出すことができます。 +`redirect` 関数を使用すると、ユーザーを別の URL にリダイレクトできます。`redirect` は、[Server Components](/docs/app/building-your-application/rendering/server-components)、[Route Handlers](/docs/app/building-your-application/routing/route-handlers)、および [Server Actions](/docs/app/building-your-application/data-fetching/server-actions-and-mutations) で呼び出すことができます。 -`redirect`は、ミューテーションまたはイベントの後によく使用されます。たとえば、投稿を作成する場合です: +`redirect` は、しばしば変更やイベントの後に使用されます。例えば、投稿を作成する場合: - + -```tsx title="app/actions.tsx" switcher +```ts title="app/actions.ts" switcher 'use server' import { redirect } from 'next/navigation' @@ -52,20 +52,20 @@ import { revalidatePath } from 'next/cache' export async function createPost(id: string) { try { - // データベースを呼び出す + // データベースを呼び出します } catch (error) { - // エラーを処理する + // エラーを処理します } - revalidatePath('/posts') // キャッシュされた投稿を更新する - redirect(`/post/${id}`) // 新しい投稿ページに移動する + revalidatePath('/posts') // キャッシュされた投稿を更新 + redirect(`/post/${id}`) // 新しい投稿ページに移動 } ``` - + -```jsx title="app/actions.js" switcher +```js title="app/actions.js" switcher 'use server' import { redirect } from 'next/navigation' @@ -73,39 +73,39 @@ import { revalidatePath } from 'next/cache' export async function createPost(id) { try { - // データベースを呼び出す + // データベースを呼び出します } catch (error) { - // エラーを処理する + // エラーを処理します } - revalidatePath('/posts') // キャッシュされた投稿を更新する - redirect(`/post/${id}`) // 新しい投稿ページに移動する + revalidatePath('/posts') // キャッシュされた投稿を更新 + redirect(`/post/${id}`) // 新しい投稿ページに移動 } ``` -> **参考情報**: +> **Good to know**: > -> - `redirect`はデフォルトで307(Temporary Redirect)ステータスコードを返します。Server Actionで使用されるとき、通常はPOSTリクエストの結果として成功ページにリダイレクトするために使用される303(See Other)を返します。 -> - `redirect`は内部でエラーをスローするため、`try/catch`ブロックの外で呼び出す必要があります。 -> - `redirect`はクライアントコンポーネントのレンダリングプロセス中に呼び出すことができますが、イベントハンドラーでは呼び出せません。[`useRouter`フック](#userouter-hook)を代わりに使用できます。 -> - `redirect`は絶対URLも受け入れ、外部リンクにリダイレクトするために使用できます。 -> - レンダープロセスの前にリダイレクトしたい場合は、[`next.config.js`](#redirects-in-nextconfigjs)または[Middleware](#nextresponseredirect-in-middleware)を使用してください。 +> - `redirect` はデフォルトで307(一時的なリダイレクト)ステータスコードを返します。Server Action で使用される場合、通常 POST リクエストの結果として成功ページにリダイレクトするために使用される303 (See Other) を返します。 +> - `redirect` は内部でエラーをスローするため、`try/catch` ブロックの外で呼び出すべきです。 +> - `redirect` は、クライアントコンポーネントのレンダリングプロセス中に呼び出すことができますが、イベントハンドラで呼び出すことはできません。代わりに、[`useRouter` フック](#userouter-hook) を使用できます。 +> - `redirect` は絶対URLも受け入れ、外部リンクへのリダイレクトに使用できます。 +> - レンダリングプロセスの前にリダイレクトしたい場合は、 [`next.config.js`](#redirects-in-nextconfigjs) または [Middleware](#nextresponseredirect-in-middleware) を使用してください。 -[`redirect` APIリファレンス](/docs/app/api-reference/functions/redirect)を参照して、さらに情報をご覧ください。 +詳細については、[`redirect` API リファレンス](/docs/app/api-reference/functions/redirect) を参照してください。 ## `permanentRedirect` 関数 {#permanentredirect-function} -`permanentRedirect` 関数は、ユーザーを別のURLに**永久に**リダイレクトすることができます。`permanentRedirect`を[Server Components](/docs/app/building-your-application/rendering/server-components)、[Route Handlers](/docs/app/building-your-application/routing/route-handlers)、および[Server Actions](/docs/app/building-your-application/data-fetching/server-actions-and-mutations)で呼び出すことができます。 +`permanentRedirect` 関数を使用すると、ユーザーを別の URL に**永久**にリダイレクトできます。`permanentRedirect` は、[Server Components](/docs/app/building-your-application/rendering/server-components)、[Route Handlers](/docs/app/building-your-application/routing/route-handlers)、および [Server Actions](/docs/app/building-your-application/data-fetching/server-actions-and-mutations) で呼び出すことができます。 -`permanentRedirect`は、エンティティの正規URLが変更されるミューテーションまたはイベントの後によく使用されます。たとえば、ユーザーがユーザー名を変更した後にプロフィールURLを更新する場合です: +`permanentRedirect` は、エンティティのカノニカル URL を変更する変更やイベントの後によく使用されます。例えば、ユーザー名を変更した後にプロファイル URL を更新する場合です。 - + -```tsx title="app/actions.ts" switcher +```ts title="app/actions.ts" switcher 'use server' import { permanentRedirect } from 'next/navigation' @@ -113,20 +113,20 @@ import { revalidateTag } from 'next/cache' export async function updateUsername(username: string, formData: FormData) { try { - // データベースを呼び出す + // データベースを呼び出します } catch (error) { - // エラーを処理する + // エラーを処理します } - revalidateTag('username') // ユーザー名のすべての参照を更新する - permanentRedirect(`/profile/${username}`) // 新しいユーザープロフィールに移動する + revalidateTag('username') // ユーザー名への全ての参照を更新します + permanentRedirect(`/profile/${username}`) // 新しいユーザープロファイルに移動します } ``` - + -```jsx title="app/actions.js" switcher +```js title="app/actions.js" switcher 'use server' import { permanentRedirect } from 'next/navigation' @@ -134,26 +134,26 @@ import { revalidateTag } from 'next/cache' export async function updateUsername(username, formData) { try { - // データベースを呼び出す + // データベースを呼び出します } catch (error) { - // エラーを処理する + // エラーを処理します } - revalidateTag('username') // ユーザー名のすべての参照を更新する - permanentRedirect(`/profile/${username}`) // 新しいユーザープロフィールに移動する + revalidateTag('username') // ユーザー名への全ての参照を更新します + permanentRedirect(`/profile/${username}`) // 新しいユーザープロファイルに移動します } ``` -> **参考情報**: +> **Good to know**: > -> - `permanentRedirect`はデフォルトで308(恒久的リダイレクト)ステータスコードを返します; -> - `permanentRedirect`は絶対URLも受け入れ、外部リンクにリダイレクトするために使用できます; -> - レンダープロセスの前にリダイレクトしたい場合は、[`next.config.js`](#redirects-in-nextconfigjs)または[Middleware](#nextresponseredirect-in-middleware)を使用してください; +> - `permanentRedirect` はデフォルトで308(永久リダイレクト)ステータスコードを返します。 +> - `permanentRedirect` は絶対URLも受け入れ、外部リンクへのリダイレクトに使用できます。 +> - レンダリングプロセスの前にリダイレクトしたい場合は、 [`next.config.js`](#redirects-in-nextconfigjs) または [Middleware](#nextresponseredirect-in-middleware) を使用してください。 -[`permanentRedirect` APIリファレンス](/docs/app/api-reference/functions/permanentRedirect)を参照して、さらに情報をご覧ください。 +詳細については、[`permanentRedirect` API リファレンス](/docs/app/api-reference/functions/permanentRedirect) を参照してください。 @@ -161,7 +161,7 @@ export async function updateUsername(username, formData) { -クライアントコンポーネントのイベントハンドラー内でリダイレクトが必要な場合、`useRouter`フックの`push`メソッドを使用できます。例えば: +クライアントコンポーネント内のイベントハンドラでリダイレクトする必要がある場合、`useRouter` フックからの `push` メソッドを使用できます。例えば: @@ -208,7 +208,7 @@ export default function Page() { -コンポーネント内でリダイレクトする必要がある場合、`useRouter`フックの`push`メソッドを使用できます。例えば: +コンポーネント内でリダイレクトする必要がある場合、`useRouter` フックからの `push` メソッドを使用できます。例えば: @@ -249,29 +249,29 @@ export default function Page() { -> **参考情報**: +> **Good to know**: > -> - プログラムでユーザーをナビゲートする必要がない場合は、[``](/docs/app/api-reference/components/link)コンポーネントを使用するべきです。 +> - ユーザーをプログラム的にナビゲートする必要がない場合は、[``](/docs/app/api-reference/components/link) コンポーネントを使用してください。 -[`useRouter` APIリファレンス](/docs/app/api-reference/functions/use-router)を参照して、さらに情報をご覧ください。 +詳細については、[`useRouter` API リファレンス](/docs/app/api-reference/functions/use-router) を参照してください。 -[`useRouter` APIリファレンス](https://nextjs.org/docs/canary/pages/api-reference/functions/use-router)を参照して、さらに情報をご覧ください。 +詳細については、[`useRouter` API リファレンス](https://nextjs.org/docs/canary/pages/api-reference/functions/use-router) を参照してください。 -## `next.config.js`内の`redirects` {#redirects-in-next-config-js} +## `next.config.js` における `redirects` {#redirects-in-next-config-js} -`next.config.js`ファイル内の`redirects`オプションを使用すると、受信リクエストのパスを別の宛先パスにリダイレクトできます。これは、ページのURL構造を変更した場合や、事前に既知のリダイレクトのリストがある場合に便利です。 +`next.config.js` ファイルの `redirects` オプションは、リクエストパスを異なるターゲットパスにリダイレクトすることを可能にします。これは、ページのURL構造を変更する場合や、事前に既知のリダイレクトのリストを持っている場合に便利です。 -`redirects`は、[パス](/docs/app/api-reference/config/next-config-js/redirects#path-matching)、[ヘッダー、cookie、クエリのマッチング](/docs/app/api-reference/config/next-config-js/redirects#header-cookie-and-query-matching)をサポートし、受信リクエストに基づいてユーザーをリダイレクトする柔軟性を提供します。 +`redirects` は[パス](/docs/app/api-reference/config/next-config-js/redirects#path-matching)、[ヘッダー、クッキー、クエリのマッチング](/docs/app/api-reference/config/next-config-js/redirects#header-cookie-and-query-matching)をサポートし、リクエストに基づいてユーザーをリダイレクトする柔軟性を提供します。 -`redirects`を使用するには、`next.config.js`ファイルにオプションを追加します: +`redirects` を使用するには、次のように `next.config.js` ファイルにオプションを追加します: ```js title="next.config.js" module.exports = { @@ -283,7 +283,7 @@ module.exports = { destination: '/', permanent: true, }, - // ワイルドカードパスマッチング + // ワイルドカードパスのマッチング { source: '/blog/:slug', destination: '/news/:slug', @@ -294,36 +294,36 @@ module.exports = { } ``` -[`redirects` APIリファレンス](/docs/app/api-reference/config/next-config-js/redirects)を参照して、さらに情報をご覧ください。 +詳細については、[`redirects` API リファレンス](/docs/app/api-reference/config/next-config-js/redirects) を参照してください。 -> **参考情報**: +> **Good to know**: > -> - `redirects`は、`permanent`オプションを使用して307(Temporary Redirect)または308(Permanent Redirect)ステータスコードを返すことができます; -> - プラットフォームによっては、`redirects`に制限がある場合があります。たとえば、Vercelでは1,024件のリダイレクトの制限があります。大量のリダイレクト(1000件以上)を管理するには、[Middleware](/docs/app/building-your-application/routing/middleware)を使用したカスタムソリューションを作成することを検討してください。規模に応じたリダイレクト管理については、[managing redirects at scale](#managing-redirects-at-scale-advanced)を参照してください; -> - `redirects`はミドルウェアの**前に**実行されます; +> - `redirects` は `permanent` オプションで、307(一時的なリダイレクト)または308(永久リダイレクト)ステータスコードを返すことができます。 +> - `redirects` にはプラットフォーム上での制限があります。例えば、Vercelでは1,024件のリダイレクト制限があります。多くのリダイレクト(1000+)を管理するには、[Middleware](/docs/app/building-your-application/routing/middleware) を使用してカスタムソリューションを作成することを検討してください。詳細は [managing redirects at scale](#managing-redirects-at-scale-advanced) をご覧ください。 +> - `redirects` は**Middlewareの前に**実行されます。 -## `NextResponse.redirect` in Middleware {#nextresponse-redirect-in-middleware} +## Middleware 内の `NextResponse.redirect` {#nextresponse-redirect-in-middleware} -ミドルウェアを使用すると、リクエストが完了する前にコードを実行できます。そして、受信リクエストに基づいて`NextResponse.redirect`を使用して別のURLにリダイレクトします。これは、条件(例:認証、セッション管理など)に基づいてユーザーをリダイレクトする場合や、大量のリダイレクトがあります: +Middleware を使用すると、リクエストが完了する前にコードを実行することができます。その後、`NextResponse.redirect` を使用して、リクエストに基づいて異なるURLにリダイレクトします。これは、条件(例:認証、セッション管理など)に基づいてユーザーをリダイレクトしたい場合や、[多くのリダイレクト](#managing-redirects-at-scale-advanced)がある場合に便利です。 -たとえば、ユーザーが認証されていない場合に`/login`ページにリダイレクトするには: +例えば、認証されていない場合にユーザーを `/login` ページにリダイレクトするには: - + -```tsx title="middleware.ts" switcher +```ts title="middleware.ts" switcher import { NextResponse, NextRequest } from 'next/server' import { authenticate } from 'auth-provider' export function middleware(request: NextRequest) { const isAuthenticated = authenticate(request) - // ユーザーが認証されている場合は、通常通り続行します + // ユーザーが認証されている場合、通常通り続行 if (isAuthenticated) { return NextResponse.next() } - // 認証されていない場合は、ログインページにリダイレクトします + // 認証されていない場合はログインページにリダイレクト return NextResponse.redirect(new URL('/login', request.url)) } @@ -342,12 +342,12 @@ import { authenticate } from 'auth-provider' export function middleware(request) { const isAuthenticated = authenticate(request) - // ユーザーが認証されている場合は、通常通り続行します + // ユーザーが認証されている場合、通常通り続行 if (isAuthenticated) { return NextResponse.next() } - // 認証されていない場合は、ログインページにリダイレクトします + // 認証されていない場合はログインページにリダイレクト return NextResponse.redirect(new URL('/login', request.url)) } @@ -359,28 +359,28 @@ export const config = { -> **参考情報**: +> **Good to know**: > -> - ミドルウェアは、`next.config.js`の`redirects`**後に**実行され、レンダリングの**前に**実行されます; +> - Middlewareは、`next.config.js` の`redirects` の**後に**実行され、レンダリングの**前に**実行されます。 -[Middleware](/docs/app/building-your-application/routing/middleware)のドキュメントを参照して、さらに情報をご覧ください。 +詳細については、 [Middleware](/docs/app/building-your-application/routing/middleware) のドキュメントを参照してください。 -## 規模に応じたリダイレクト管理(高度) {#managing-redirects-at-scale-advanced} +## 大規模なリダイレクトの管理(高度な内容) {#managing-redirects-at-scale-advanced} -大量のリダイレクト(1000件以上)を管理するために、ミドルウェアを使用してカスタムソリューションを作成することを検討してください。これにより、アプリケーションを再デプロイすることなく、プログラムでリダイレクトを処理できます。 +大量のリダイレクト(1000+)を管理するには、Middleware を使用してカスタムソリューションを作成することを検討する必要があります。これにより、アプリケーションを再デプロイする必要なく、リダイレクトをプログラム的に処理できます。 -これを行うには、以下を考慮する必要があります: +これを行うには、以下の要素を考慮する必要があります: 1. リダイレクトマップの作成と保存 2. データ検索パフォーマンスの最適化 -> **Next.jsの例**:以下の推奨事項の実装については、[Middleware with Bloom filter](https://redirects-bloom-filter.vercel.app/)の例を参照してください。 +> **Next.js Example**: 以下の推奨事項を実装する [Middleware とブルームフィルター](https://redirects-bloom-filter.vercel.app/) の例をご覧ください。 ### 1. リダイレクトマップの作成と保存 {#1-creating-and-storing-a-redirect-map} -リダイレクトマップは、データベース(通常はキー・バリュー・ストア)またはJSONファイルに保存できるリダイレクトのリストです。 +リダイレクトマップは、データベース(通常はキー・バリューストア)または JSON ファイルに保存できるリダイレクトのリストです。 -次のデータ構造を考慮してください: +以下のデータ構造を考慮してください: ```json { @@ -395,12 +395,12 @@ export const config = { } ``` -[Middleware](/docs/app/building-your-application/routing/middleware)で、Vercelの[Edge Config](https://vercel.com/docs/storage/edge-config/get-started?utm_source=next-site&utm_medium=docs&utm_campaign=next-website)や[Redis](https://vercel.com/docs/storage/vercel-kv?utm_source=next-site&utm_medium=docs&utm_campaign=next-website)などのデータベースから読み取り、受信リクエストに基づいてユーザーをリダイレクトすることができます: +[Middleware](/docs/app/building-your-application/routing/middleware) では、Vercel の [Edge Config](https://vercel.com/docs/storage/edge-config/get-started?utm_source=next-site&utm_medium=docs&utm_campaign=next-website) や [Redis](https://vercel.com/docs/storage/vercel-kv?utm_source=next-site&utm_medium=docs&utm_campaign=next-website) などのデータベースから読み込み、リクエストに基づいてユーザーをリダイレクトすることができます: - + -```tsx title="middleware.ts" switcher +```ts title="middleware.ts" switcher import { NextResponse, NextRequest } from 'next/server' import { get } from '@vercel/edge-config' @@ -419,7 +419,7 @@ export async function middleware(request: NextRequest) { return NextResponse.redirect(redirectEntry.destination, statusCode) } - // リダイレクトが見つからなかった場合、そのまま継続します + // リダイレクトが見つからない場合、リダイレクトせずに続行 return NextResponse.next() } ``` @@ -441,7 +441,7 @@ export async function middleware(request) { return NextResponse.redirect(redirectEntry.destination, statusCode) } - // リダイレクトが見つからなかった場合、そのまま継続します + // リダイレクトが見つからない場合、リダイレクトせずに続行 return NextResponse.next() } ``` @@ -451,19 +451,19 @@ export async function middleware(request) { ### 2. データ検索パフォーマンスの最適化 {#2-optimizing-data-lookup-performance} -大規模データセットをすべての受信リクエストのために読み取ることは遅く、費用がかかります。データ検索パフォーマンスを最適化する方法は2つあります: +すべてのリクエストの読み取り時に大規模なデータセットを処理することは、低速かつコストがかかります。データ検索パフォーマンスを最適化する方法は2つあります: -- [Vercel Edge Config](https://vercel.com/docs/storage/edge-config/get-started?utm_source=next-site&utm_medium=docs&utm_campaign=next-website)や[Redis](https://vercel.com/docs/storage/vercel-kv?utm_source=next-site&utm_medium=docs&utm_campaign=next-website)などの、高速読み取りに最適化されたデータベースを使用します; -- [ブルームフィルター](https://en.wikipedia.org/wiki/Bloom_filter)のようなデータ検索戦略を使用して、リダイレクトが存在するかどうかを効率的にチェックし、より大きなリダイレクトファイルやデータベースを読み取る**前に**行います; +- [Vercel Edge Config](https://vercel.com/docs/storage/edge-config/get-started?utm_source=next-site&utm_medium=docs&utm_campaign=next-website) や [Redis](https://vercel.com/docs/storage/vercel-kv?utm_source=next-site&utm_medium=docs&utm_campaign=next-website) など、高速読み取りに最適化されたデータベースを使用します。 +- データルックアップ戦略を使用し、[ブルームフィルター](https://en.wikipedia.org/wiki/Bloom_filter) のように、**大きなリダイレクトファイルやデータベースを読む**前に、リダイレクトが存在するかどうかを効率的に確認します。 -前述の例では、生成されたブルームフィルターファイルをミドルウェアにインポートし、受信リクエストのパス名がブルームフィルターに存在するかどうかを確認します。 +前の例を考慮すると、生成されたブルームフィルタファイルを Middleware にインポートし、リクエストのパス名がブルームフィルタ内に存在するかどうかを確認できます。 -存在する場合は、要求を[API Routes](https://nextjs.org/docs/canary/pages/building-your-application/routing/api-routes) [Route Handler](/docs/app/building-your-application/routing/route-handlers)に転送し、要求が実際に存在するかをチェックし、ユーザーを適切なURLにリダイレクトします。これにより、ミドルウェアに大量のリダイレクトファイルをインポートすることを避けることができ、すべての受信リクエストが遅くなるのを防ぎます。 +存在する場合、そのリクエストを [Route Handler](/docs/app/building-your-application/routing/route-handlers) [API Routes](https://nextjs.org/docs/canary/pages/building-your-application/routing/api-routes) に転送し、実際のファイルをチェックしてユーザーを適切なURLにリダイレクトします。これにより、Middleware に大量のリダイレクトファイルをインポートすることが避けられ、リクエストがすべて遅くなるのを防げます。 - + -```tsx title="middleware.ts" switcher +```ts title="middleware.ts" switcher import { NextResponse, NextRequest } from 'next/server' import { ScalableBloomFilter } from 'bloom-filters' import GeneratedBloomFilter from './redirects/bloom-filter.json' @@ -473,23 +473,23 @@ type RedirectEntry = { permanent: boolean } -// 生成されたJSONファイルからブルームフィルターを初期化する +// 生成された JSON ファイルからブルームフィルターを初期化 const bloomFilter = ScalableBloomFilter.fromJSON(GeneratedBloomFilter as any) export async function middleware(request: NextRequest) { - // 受信リクエストのパスを取得する + // リクエストのパスを取得 const pathname = request.nextUrl.pathname - // パスがブルームフィルターにあるかチェックする + // パスがブルームフィルターに存在するか確認 if (bloomFilter.has(pathname)) { - // パス名をRoute Handlerに転送する + // パス名を Route Handler に転送 const api = new URL( `/api/redirects?pathname=${encodeURIComponent(request.nextUrl.pathname)}`, request.nextUrl.origin ) try { - // Route Handlerからリダイレクトデータを取得する + // ルートハンドラからリダイレクトデータを取得 const redirectData = await fetch(api) if (redirectData.ok) { @@ -497,10 +497,10 @@ export async function middleware(request: NextRequest) { await redirectData.json() if (redirectEntry) { - // ステータスコードを決定する + // ステータスコードを決定 const statusCode = redirectEntry.permanent ? 308 : 307 - // 宛先にリダイレクトする + // 宛先にリダイレクト return NextResponse.redirect(redirectEntry.destination, statusCode) } } @@ -509,7 +509,7 @@ export async function middleware(request: NextRequest) { } } - // リダイレクトが見つからなかった場合、そのままリクエストを続行します + // リダイレクトが見つからない場合、リダイレクトせずにリクエストを続行 return NextResponse.next() } ``` @@ -522,33 +522,33 @@ import { NextResponse } from 'next/server' import { ScalableBloomFilter } from 'bloom-filters' import GeneratedBloomFilter from './redirects/bloom-filter.json' -// 生成されたJSONファイルからブルームフィルターを初期化する +// 生成された JSON ファイルからブルームフィルターを初期化 const bloomFilter = ScalableBloomFilter.fromJSON(GeneratedBloomFilter) export async function middleware(request) { - // 受信リクエストのパスを取得する + // リクエストのパスを取得 const pathname = request.nextUrl.pathname - // パスがブルームフィルターにあるかチェックする + // パスがブルームフィルターに存在するか確認 if (bloomFilter.has(pathname)) { - // パス名をRoute Handlerに転送する + // パス名を Route Handler に転送 const api = new URL( `/api/redirects?pathname=${encodeURIComponent(request.nextUrl.pathname)}`, request.nextUrl.origin ) try { - // Route Handlerからリダイレクトデータを取得する + // ルートハンドラからリダイレクトデータを取得 const redirectData = await fetch(api) if (redirectData.ok) { const redirectEntry = await redirectData.json() if (redirectEntry) { - // ステータスコードを決定する + // ステータスコードを決定 const statusCode = redirectEntry.permanent ? 308 : 307 - // 宛先にリダイレクトする + // 宛先にリダイレクト return NextResponse.redirect(redirectEntry.destination, statusCode) } } @@ -557,7 +557,7 @@ export async function middleware(request) { } } - // リダイレクトが見つからなかった場合、そのままリクエストを続行します + // リダイレクトが見つからない場合、リダイレクトせずにリクエストを続行 return NextResponse.next() } ``` @@ -567,12 +567,12 @@ export async function middleware(request) { -その後、Route Handlerでは: +次に、Route Handler で: - + -```tsx title="app/redirects/route.ts" switcher +```ts title="app/api/redirects/route.ts" switcher import { NextRequest, NextResponse } from 'next/server' import redirects from '@/app/redirects/redirects.json' @@ -584,18 +584,18 @@ type RedirectEntry = { export function GET(request: NextRequest) { const pathname = request.nextUrl.searchParams.get('pathname') if (!pathname) { - return new Response('不正なリクエスト', { status: 400 }) + return new Response('Bad Request', { status: 400 }) } - // redirects.jsonファイルからリダイレクトエントリを取得する + // redirects.json ファイルからリダイレクトエントリを取得 const redirect = (redirects as Record)[pathname] - // ブルームフィルターの誤検知に対応する + // ブルームフィルターの誤検出を考慮 if (!redirect) { - return new Response('リダイレクトなし', { status: 400 }) + return new Response('No redirect', { status: 400 }) } - // リダイレクトエントリを返す + // リダイレクトエントリを返却 return NextResponse.json(redirect) } ``` @@ -603,25 +603,25 @@ export function GET(request: NextRequest) { -```js title="app/redirects/route.js" switcher +```js title="app/api/redirects/route.js" switcher import { NextResponse } from 'next/server' import redirects from '@/app/redirects/redirects.json' export function GET(request) { const pathname = request.nextUrl.searchParams.get('pathname') if (!pathname) { - return new Response('不正なリクエスト', { status: 400 }) + return new Response('Bad Request', { status: 400 }) } - // redirects.jsonファイルからリダイレクトエントリを取得する + // redirects.json ファイルからリダイレクトエントリを取得 const redirect = redirects[pathname] - // ブルームフィルターの誤検知に対応する + // ブルームフィルターの誤検出を考慮 if (!redirect) { - return new Response('リダイレクトなし', { status: 400 }) + return new Response('No redirect', { status: 400 }) } - // リダイレクトエントリを返す + // リダイレクトエントリを返却 return NextResponse.json(redirect) } ``` @@ -633,12 +633,12 @@ export function GET(request) { -その後、API Routeでは: +次に、API Route で: - + -```tsx title="pages/api/redirects.ts" switcher +```ts title="pages/api/redirects.ts" switcher import type { NextApiRequest, NextApiResponse } from 'next' import redirects from '@/app/redirects/redirects.json' @@ -650,18 +650,18 @@ type RedirectEntry = { export default function handler(req: NextApiRequest, res: NextApiResponse) { const pathname = req.query.pathname if (!pathname) { - return res.status(400).json({ message: '不正なリクエスト' }) + return res.status(400).json({ message: 'Bad Request' }) } - // redirects.jsonファイルからリダイレクトエントリを取得する + // redirects.json ファイルからリダイレクトエントリを取得 const redirect = (redirects as Record)[pathname] - // ブルームフィルターの誤検知に対応する + // ブルームフィルターの誤検出を考慮 if (!redirect) { - return res.status(400).json({ message: 'リダイレクトなし' }) + return res.status(400).json({ message: 'No redirect' }) } - // リダイレクトエントリを返す + // リダイレクトエントリを返却 return res.json(redirect) } ``` @@ -675,18 +675,18 @@ import redirects from '@/app/redirects/redirects.json' export default function handler(req, res) { const pathname = req.query.pathname if (!pathname) { - return res.status(400).json({ message: '不正なリクエスト' }) + return res.status(400).json({ message: 'Bad Request' }) } - // redirects.jsonファイルからリダイレクトエントリを取得する + // redirects.json ファイルからリダイレクトエントリを取得 const redirect = redirects[pathname] - // ブルームフィルターの誤検知に対応する + // ブルームフィルターの誤検出を考慮 if (!redirect) { - return res.status(400).json({ message: 'リダイレクトなし' }) + return res.status(400).json({ message: 'No redirect' }) } - // リダイレクトエントリを返す + // リダイレクトエントリを返却 return res.json(redirect) } ``` @@ -696,7 +696,7 @@ export default function handler(req, res) { -> **参考情報**: +> **Good to know:** > -> - ブルームフィルターを生成するために、[`bloom-filters`](https://www.npmjs.com/package/bloom-filters)のようなライブラリを使用できます; -> - 悪意のあるリクエストを防止するために、Route Handlerに対して行われるリクエストを検証する必要があります; +> - ブルームフィルターを生成するには、[`bloom-filters`](https://www.npmjs.com/package/bloom-filters) のようなライブラリを使用できます。 +> - 悪意のあるリクエストを防ぐために、Route Handler に行うリクエストを検証すべきです。 diff --git a/docs/01-app/02-building-your-application/01-routing/15-internationalization.mdx b/docs/01-app/02-building-your-application/01-routing/15-internationalization.mdx index 1d78b7d..90bbec6 100644 --- a/docs/01-app/02-building-your-application/01-routing/15-internationalization.mdx +++ b/docs/01-app/02-building-your-application/01-routing/15-internationalization.mdx @@ -1,22 +1,22 @@ --- -title: '国際化' -description: '国際化されたルーティングと地域化されたコンテンツで複数言語のサポートを追加します' +title: 'Internationalization' +description: '多言語対応のルーティングとローカライズされたコンテンツで複数の言語をサポートします' --- -Next.jsは、コンテンツのルーティングとレンダリングを構成して、複数の言語をサポートすることを可能にします。異なるロケールにサイトを適応させることには、翻訳されたコンテンツ(地域化)と国際化されたルートが含まれます。 +Next.jsは、複数の言語をサポートするためのルーティングとコンテンツのレンダリングを設定できます。異なるロケールに適応させるには、翻訳されたコンテンツ(ローカライゼーション)と国際化されたルートを含みます。 ## 用語 {#terminology} -- **Locale:** 一連の言語および形式設定の優先事項の識別子。通常、ユーザーの好みの言語とおそらく地理的な地域が含まれます。 - - `en-US`: アメリカで話される英語 +- **Locale:** 言語とフォーマットの設定を識別するための識別子。通常、ユーザーの好ましい言語とおそらくその地理的地域が含まれます。 + - `en-US`: アメリカ合衆国で話される英語 - `nl-NL`: オランダで話されるオランダ語 - - `nl`: 特定の地域が指定されていないオランダ語 + - `nl`: 特定の地域を指定しないオランダ語 ## ルーティングの概要 {#routing-overview} -ブラウザでのユーザーの言語優先順位を使用して、どのロケールを使用するかを選択することをお勧めします。好みの言語を変更すると、アプリケーションに到着する`Accept-Language`ヘッダーが変更されます。 +ブラウザのユーザーの言語設定を使用して、使用するロケールを選択することを推奨します。好みの言語を変更すると、`Accept-Language`ヘッダーがアプリケーションに送信されます。 -例えば、以下のライブラリを使用して、受信する`Request`を見て、`Headers`、サポート予定のロケール、およびデフォルトのロケールに基づいて、どのロケールを選択するかを決定することができます。 +たとえば、以下のライブラリを使用して、`Request`を確認し、`Headers`、サポート予定のロケール、デフォルトのロケールに基づいて使用するロケールを選択できます。 ```js title="middleware.js" import { match } from '@formatjs/intl-localematcher' @@ -30,18 +30,18 @@ let defaultLocale = 'en-US' match(languages, locales, defaultLocale) // -> 'en-US' ``` -ルーティングはサブパス (`/fr/products`) またはドメイン (`my-site.fr/products`) を使用して国際化できます。この情報を使用して、[Middleware](/docs/app/building-your-application/routing/middleware)内でロケールに基づいてユーザーをリダイレクトすることができます。 +ルーティングはサブパス(`/fr/products`)やドメイン(`my-site.fr/products`)で国際化できます。この情報をもとに、[Middleware](/docs/app/building-your-application/routing/middleware)内でロケールに基づいてユーザーをリダイレクトできます。 ```js title="middleware.js" import { NextResponse } from "next/server"; let locales = ['en-US', 'nl-NL', 'nl'] -// 上記と同様にまたはライブラリを用いて、好みのロケールを取得する +// 上記に似た方法やライブラリを使用して優先ロケールを取得 function getLocale(request) { ... } export function middleware(request) { - // パス名にサポートされているロケールがあるかどうかを確認 + // パス名にサポートされているロケールが含まれているかどうかを確認 const { pathname } = request.nextUrl const pathnameHasLocale = locales.some( (locale) => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}` @@ -52,38 +52,38 @@ export function middleware(request) { // ロケールがない場合はリダイレクト const locale = getLocale(request) request.nextUrl.pathname = `/${locale}${pathname}` - // 例: 受信リクエストが/productsの場合 + // 例: リクエストが/productsなら // 新しいURLは/en-US/productsになります return NextResponse.redirect(request.nextUrl) } export const config = { matcher: [ - // すべての内部パス (_next) をスキップ + // 内部パスすべてをスキップ (_next) '/((?!_next).*)', - // 任意: root (/) URL でのみ実行 + // 任意: ルート (/) URL のみで実行 // '/' ], } ``` -最後に、`app/`内のすべての特別なファイルが`app/[lang]`の下にネストされていることを確認してください。これにより、Next.js routerはルート内の異なるロケールを動的に処理し、`lang`パラメータをすべてのレイアウトとページに転送できるようになります。例えば: +最後に、`app/` 内の特別なファイルがすべて `app/[lang]` にネストされていることを確認します。これにより、Next.jsのrouterがルート内の異なるロケールを動的に処理し、`lang`パラメーターをすべてのレイアウトとページに転送できるようになります。例: ```jsx title="app/[lang]/page.js" -// 現在のロケールにアクセスできるようになります -// 例: /en-US/products -> `lang`は"en-US" +// 現在のロケールにアクセスできます +// 例: /en-US/products -> `lang` は "en-US" export default async function Page({ params: { lang } }) { return ... } ``` -root レイアウトも新しいフォルダー(例: `app/[lang]/layout.js`)にネストできます。 +root レイアウトも新しいフォルダーにネストできます(例: `app/[lang]/layout.js`)。 -## 地域化 {#localization} +## ローカライゼーション {#localization} -ユーザーの好みのロケールに基づいて表示されるコンテンツを変更する、つまり地域化はNext.jsに特有のものではありません。以下で説明するパターンは、任意のWebアプリケーションでも同様に機能します。 +ユーザーの好みのロケールに基づいて表示されるコンテンツを変更すること、つまりローカライゼーションは、Next.jsに特有のものではありません。以下に記載されたパターンは、どのWebアプリケーションでも同様に機能します。 -アプリケーション内で英語とオランダ語のコンテンツの両方をサポートしたいと仮定しましょう。いくつかのキーから地域化された文字列へのマッピングを提供するオブジェクトである2つの異なる「辞書」を管理するかもしれません。例えば: +私たちのアプリケーション内で、英語とオランダ語の両方のコンテンツをサポートしたいとします。キーからローカライズされた文字列へのマッピングを提供する2つの異なる「辞書」を保つことができます。例: ```json title="dictionaries/en.json" { @@ -101,7 +101,7 @@ root レイアウトも新しいフォルダー(例: `app/[lang]/layout.js`) } ``` -次に、要求されたロケールの翻訳をロードするための`getDictionary`関数を作成できます: +次に、リクエストされたロケールの翻訳を読み込むための`getDictionary`関数を作成できます: ```jsx title="app/[lang]/dictionaries.js" import 'server-only' @@ -114,22 +114,22 @@ const dictionaries = { export const getDictionary = async (locale) => dictionaries[locale]() ``` -現在選択されている言語に基づいて、レイアウトやページ内で辞書を取得できます。 +現在選択されている言語を考慮し、レイアウトやページ内で辞書を取得できます。 ```jsx title="app/[lang]/page.js" import { getDictionary } from './dictionaries' export default async function Page({ params: { lang } }) { const dict = await getDictionary(lang) // en - return // カートに追加 + return // Add to Cart } ``` -`app/`ディレクトリ内のすべてのレイアウトとページがデフォルトで[Server Components](/docs/app/building-your-application/rendering/server-components)であるため、翻訳ファイルのサイズがクライアント側JavaScriptバンドルサイズに影響を与えることを心配する必要はありません。このコードは**サーバー上でのみ実行され**、結果として得られるHTMLのみがブラウザーに送信されます。 +`app/` ディレクトリ内のすべてのレイアウトとページが[Server Components](/docs/app/building-your-application/rendering/server-components)をデフォルトで使用するため、クライアント側のJavaScriptバンドルのサイズに翻訳ファイルが影響することを心配する必要はありません。このコードは**サーバーでのみ実行**され、結果として生じたHTMLだけがブラウザに送信されます。 ## 静的生成 {#static-generation} -特定のロケールセットに対して静的ルートを生成するには、`generateStaticParams`をページやレイアウトで使用します。例えば、root レイアウトでこれをグローバルに行うことができます: +特定のロケールセットに対して静的ルートを生成するために、任意のページまたはレイアウトで`generateStaticParams`を使用できます。たとえば、root レイアウトにおいてグローバルに使用できます: ```jsx title="app/[lang]/layout.js" export async function generateStaticParams() { @@ -147,7 +147,7 @@ export default function Root({ children, params }) { ## リソース {#resources} -- [Minimal i18n routing and translations](https://github.com/vercel/next.js/tree/canary/examples/app-dir-i18n-routing) +- [ミニマルなi18nルーティングと翻訳](https://github.com/vercel/next.js/tree/canary/examples/i18n-routing) - [`next-intl`](https://next-intl-docs.vercel.app/docs/next-13) - [`next-international`](https://github.com/QuiiBz/next-international) - [`next-i18n-router`](https://github.com/i18nexus/next-i18n-router) diff --git a/docs/01-app/02-building-your-application/02-data-fetching/01-fetching.mdx b/docs/01-app/02-building-your-application/02-data-fetching/01-fetching.mdx index 357b81e..c81ffdb 100644 --- a/docs/01-app/02-building-your-application/02-data-fetching/01-fetching.mdx +++ b/docs/01-app/02-building-your-application/02-data-fetching/01-fetching.mdx @@ -1,7 +1,7 @@ --- -title: 'データ取得とキャッシュ' -nav_title: 'データ取得とキャッシュ' -description: 'Next.jsでサーバーまたはクライアントでデータを取得するためのベストプラクティスを学びましょう。' +title: 'Data Fetching and Caching' +nav_title: 'Data Fetching and Caching' +description: 'Next.jsでサーバーまたはクライアントでデータを取得するためのベストプラクティスを学びます.' ---
@@ -13,17 +13,17 @@ description: 'Next.jsでサーバーまたはクライアントでデータを
-このガイドでは、Next.jsにおけるデータ取得とキャッシュの基本を実用的な例とベストプラクティスを示しながら説明します。 +このガイドでは、Next.jsにおけるデータ取得とキャッシュの基本について説明し、実例とベストプラクティスを提供します。 -Next.jsにおけるデータ取得の最小限の例を以下に示します: +次に示すのは、Next.jsでのデータ取得の最小限の例です: ```tsx title="app/page.tsx" switcher export default async function Page() { - let data = await fetch('https://api.vercel.app/blog') - let posts = await data.json() + const data = await fetch('https://api.vercel.app/blog') + const posts = await data.json() return (
    {posts.map((post) => ( @@ -39,8 +39,8 @@ export default async function Page() { ```jsx title="app/page.js" switcher export default async function Page() { - let data = await fetch('https://api.vercel.app/blog') - let posts = await data.json() + const data = await fetch('https://api.vercel.app/blog') + const posts = await data.json() return (
      {posts.map((post) => ( @@ -54,9 +54,9 @@ export default async function Page() { -この例は、非同期のReact Server Componentで`fetch` APIを使用してサーバー側でデータを取得する基本的な方法を示しています。 +この例は、非同期のReact server componentにおける`fetch` APIを用いた基本的なサーバーサイドでのデータ取得を示しています。 -## 参考 {#reference} +## 参照 {#reference} - [`fetch`](/docs/app/api-reference/functions/fetch) - React [`cache`](https://react.dev/reference/react/cache) @@ -64,17 +64,17 @@ export default async function Page() { ## 例 {#examples} -### サーバーで`fetch` APIを使用したデータ取得 {#fetching-data-on-the-server-with-the-fetch-api} +### `fetch` APIを用いてサーバーでデータを取得する {#fetching-data-on-the-server-with-the-fetch-api} -このコンポーネントはブログ投稿のリストを取得して表示します。`fetch`からのレスポンスはデフォルトではキャッシュされません。 +このコンポーネントはブログ投稿のリストを取得して表示します;`fetch`のレスポンスはデフォルトではキャッシュされません。 ```tsx title="app/page.tsx" switcher export default async function Page() { - let data = await fetch('https://api.vercel.app/blog') - let posts = await data.json() + const data = await fetch('https://api.vercel.app/blog') + const posts = await data.json() return (
        {posts.map((post) => ( @@ -90,8 +90,8 @@ export default async function Page() { ```jsx title="app/page.js" switcher export default async function Page() { - let data = await fetch('https://api.vercel.app/blog') - let posts = await data.json() + const data = await fetch('https://api.vercel.app/blog') + const posts = await data.json() return (
          {posts.map((post) => ( @@ -105,19 +105,19 @@ export default async function Page() { -このルートの他の場所で[Dynamic APIs](/docs/app/building-your-application/rendering/server-components#dynamic-rendering)を使用していない場合、`next build`中にこのページは静的ページとして事前レンダリングされます。その後、データは[Incremental Static Regeneration](/docs/app/building-your-application/data-fetching/incremental-static-regeneration)を使用して更新できます。 +このルートの他のどこでも[Dynamic APIs](/docs/app/building-your-application/rendering/server-components#dynamic-rendering)を使用していない場合、このルートは`next build`の間に静的ページとして事前レンダリングされます;そのデータは[Incremental Static Regeneration](/docs/app/building-your-application/data-fetching/incremental-static-regeneration)を使用して更新することができます。 -ページの事前レンダリングを防ぐには、以下をファイルに追加します: +ページを事前レンダリングしないようにするには、ファイルに次のコードを追加します: ```js export const dynamic = 'force-dynamic' ``` -ただし、多くの場合、`cookies`、`headers`、またはページpropsからの`searchParams`を読み取る関数を使用します。これによりページは自動的に動的にレンダリングされます。この場合、`force-dynamic`を明示的に使用する必要はありません。 +ただし、通常`cookies`や`headers`、ページpropsから`searchParams`を読み取るといった関数を使用するため、ページは自動的に動的にレンダリングされます;この場合、明示的に`force-dynamic`を使用する必要はありません。 -### ORMまたはデータベースを使用してサーバーでデータ取得 {#fetching-data-on-the-server-with-an-orm-or-database} +### ORMやデータベースを利用してサーバーでデータを取得する {#fetching-data-on-the-server-with-an-orm-or-database} -このコンポーネントはブログ投稿のリストを取得して表示します。データベースからのレスポンスはデフォルトではキャッシュされていませんが、[追加の設定](#caching-data-with-an-orm-or-database)によってキャッシュすることができます。 +このコンポーネントはブログポストのリストを取得し表示します;データベースのレスポンスはデフォルトではキャッシュされませんが、[追加の設定](#caching-data-with-an-orm-or-database)を行うことで可能です。 @@ -126,7 +126,7 @@ export const dynamic = 'force-dynamic' import { db, posts } from '@/lib/db' export default async function Page() { - let allPosts = await db.select().from(posts) + const allPosts = await db.select().from(posts) return (
            {allPosts.map((post) => ( @@ -144,7 +144,7 @@ export default async function Page() { import { db, posts } from '@/lib/db' export default async function Page() { - let allPosts = await db.select().from(posts) + const allPosts = await db.select().from(posts) return (
              {allPosts.map((post) => ( @@ -158,21 +158,21 @@ export default async function Page() { -このルートの他の場所で[Dynamic APIs](/docs/app/building-your-application/rendering/server-components#dynamic-rendering)を使用していない場合、`next build`中にこのページは静的ページとして事前レンダリングされます。その後、データは[Incremental Static Regeneration](/docs/app/building-your-application/data-fetching/incremental-static-regeneration)を使用して更新できます。 +このルートで[Dynamic APIs](/docs/app/building-your-application/rendering/server-components#dynamic-rendering)を使用しない場合、`next build`時に静的ページとして事前レンダリングされます;そのデータは[Incremental Static Regeneration](/docs/app/building-your-application/data-fetching/incremental-static-regeneration)を使って更新できます。 -ページの事前レンダリングを防ぐには、以下をファイルに追加します: +ページを事前レンダリングしないためには、次のコードをファイルに追加します: ```js export const dynamic = 'force-dynamic' ``` -ただし、多くの場合、`cookies`、`headers`、またはページpropsからの`searchParams`を読み取る関数を使用します。これによりページは自動的に動的にレンダリングされます。この場合、`force-dynamic`を明示的に使用する必要はありません。 +ただし、通常は`cookies`、`headers`、またはページpropsから`searchParams`を読み取るなどの関数を使用するため、ページは自動的に動的にレンダリングされます;この場合、`force-dynamic`を明示的に使用する必要はありません。 ### クライアントでデータを取得する {#fetching-data-on-the-client} -最初にサーバーサイドでデータを取得することをお勧めします。 +まずはサーバーサイドでデータを取得することをお勧めします。 -ただし、クライアントサイドのデータ取得が理にかなう場合もあります。その際には、`useEffect`で手動で`fetch`を呼び出す(推奨されません)か、クライアント取得のためにコミュニティの人気のあるReactライブラリ(例:[SWR](https://swr.vercel.app/)や[React Query](https://tanstack.com/query/latest))を利用することができます。 +しかし、クライアントサイドでのデータ取得が意味を持つケースもあります。こうしたシナリオでは、手動で`useEffect`内で`fetch`を呼び出す(推奨されない)か、クライアント取得のためのコミュニティの人気のあるReactライブラリ([SWR](https://swr.vercel.app/)や[React Query](https://tanstack.com/query/latest)など)を活用できます。 @@ -187,8 +187,8 @@ export function Posts() { useEffect(() => { async function fetchPosts() { - let res = await fetch('https://api.vercel.app/blog') - let data = await res.json() + const res = await fetch('https://api.vercel.app/blog') + const data = await res.json() setPosts(data) } fetchPosts() @@ -219,8 +219,8 @@ export function Posts() { useEffect(() => { async function fetchPosts() { - let res = await fetch('https://api.vercel.app/blog') - let data = await res.json() + const res = await fetch('https://api.vercel.app/blog') + const data = await res.json() setPosts(data) } fetchPosts() @@ -241,9 +241,9 @@ export function Posts() { -### ORMまたはデータベースによるデータキャッシュ {#caching-data-with-an-orm-or-database} +### ORMまたはデータベースでデータをキャッシュする {#caching-data-with-an-orm-or-database} -`unstable_cache` APIを使用してレスポンスをキャッシュし、`next build`実行時にページを事前レンダリングすることができます。 +`unstable_cache` APIを利用してレスポンスをキャッシュすると、`next build`を実行する際にページを事前レンダリングすることができます。 @@ -304,22 +304,22 @@ export default async function Page() { -この例では、データベースクエリの結果を1時間(3600秒)キャッシュしています。また、キャッシュタグ`posts`を追加しており、後で[Incremental Static Regeneration](/docs/app/building-your-application/data-fetching/incremental-static-regeneration)でインバリデートすることができます。 +この例では、データベースクエリの結果が1時間(3600秒)キャッシュされます。また、キャッシュタグ`posts`が追加され、[Incremental Static Regeneration](/docs/app/building-your-application/data-fetching/incremental-static-regeneration)で無効化することができます。 ### 複数の関数でデータを再利用する {#reusing-data-across-multiple-functions} -Next.jsは、`generateMetadata`や`generateStaticParams`といったAPIを使用します。これらのAPIでは、`page`で取得したデータを使う必要があります。 +Next.jsはAPIsの一部として`generateMetadata`や`generateStaticParams`を使用しています。これらでは`page`で取得したのと同じデータが必要になることがあります。 -もし`fetch`を使用している場合、リクエストに`cache: 'force-cache'`を追加するとリクエストが[メモ化](/docs/app/building-your-application/caching#request-memoization)されます。これにより、同じオプションで同じURLを安全に呼び出すことができ、リクエストは1回のみ行われます。 +`fetch`を使用している場合、リクエストは`cache: 'force-cache'`を追加することで[memoize](/docs/app/building-your-application/caching#request-memoization)できます。これにより、同じURLに同じオプションで安全に呼び出すことができ、1回のリクエストのみが行われます。 -> **Good to know:** +> **Good to know:** > -> - 以前のバージョンのNext.jsでは、`fetch`を使用するとデフォルトの`cache`値は`force-cache`でした。バージョン15では、デフォルトが`cache: no-store`に変更されました。 +> - 以前のバージョンのNext.jsでは、`fetch`使用時にデフォルトの`cache`値が`force-cache`でした;これはバージョン15で`cache: no-store`がデフォルトに変更されました。 -```tsx title="app/page.tsx" switcher +```tsx title="app/blog/[id]/page.tsx" switcher import { notFound } from 'next/navigation' interface Post { @@ -329,21 +329,21 @@ interface Post { } async function getPost(id: string) { - let res = await fetch(`https://api.vercel.app/blog/${id}`, { + const res = await fetch(`https://api.vercel.app/blog/${id}`, { cache: 'force-cache', }) - let post: Post = await res.json() + const post: Post = await res.json() if (!post) notFound() return post } export async function generateStaticParams() { - let posts = await fetch('https://api.vercel.app/blog', { + const posts = await fetch('https://api.vercel.app/blog', { cache: 'force-cache', }).then((res) => res.json()) return posts.map((post: Post) => ({ - id: post.id, + id: String(post.id), })) } @@ -352,7 +352,8 @@ export async function generateMetadata({ }: { params: Promise<{ id: string }> }) { - let post = await getPost(params.id) + const { id } = await params + const post = await getPost(id) return { title: post.title, @@ -364,7 +365,8 @@ export default async function Page({ }: { params: Promise<{ id: string }> }) { - let post = await getPost(params.id) + const { id } = await params + const post = await getPost(id) return (
              @@ -378,28 +380,29 @@ export default async function Page({ -```jsx title="app/page.js" switcher +```jsx title="app/blog/[id]/page.js" switcher import { notFound } from 'next/navigation' async function getPost(id) { - let res = await fetch(`https://api.vercel.app/blog/${id}`) - let post = await res.json() + const res = await fetch(`https://api.vercel.app/blog/${id}`) + const post = await res.json() if (!post) notFound() return post } export async function generateStaticParams() { - let posts = await fetch('https://api.vercel.app/blog').then((res) => + const posts = await fetch('https://api.vercel.app/blog').then((res) => res.json() ) return posts.map((post) => ({ - id: post.id, + id: String(post.id), })) } export async function generateMetadata({ params }) { - let post = await getPost(params.id) + const { id } = await params + const post = await getPost(id) return { title: post.title, @@ -407,7 +410,8 @@ export async function generateMetadata({ params }) { } export default async function Page({ params }) { - let post = await getPost(params.id) + const { id } = await params + const post = await getPost(id) return (
              @@ -421,11 +425,11 @@ export default async function Page({ params }) { -もし`fetch`を使用していない場合、ORMやデータベースを直接使用する代わりに、Reactの`cache`関数でデータ取得をラップできます。これにより重複が排除され、クエリは1回のみ行われます。 +`fetch`を使用していない場合や、ORMやデータベースを直接使用している場合、データ取得をReactの`cache`関数でラップすることができます。これにより、データ取得が重複せず、1つのクエリだけが実行されます。 ```jsx import { cache } from 'react' -import { db, posts, eq } from '@/lib/db' // Drizzle ORMでの例 +import { db, posts, eq } from '@/lib/db' // Example with Drizzle ORM import { notFound } from 'next/navigation' export const getPost = cache(async (id) => { @@ -440,47 +444,48 @@ export const getPost = cache(async (id) => { ### キャッシュされたデータの再検証 {#revalidating-cached-data} -[Incremental Static Regeneration](/docs/app/building-your-application/data-fetching/incremental-static-regeneration)を使用したキャッシュされたデータの再検証について詳しく学びましょう。 +[Incremental Static Regeneration](/docs/app/building-your-application/data-fetching/incremental-static-regeneration)を用いたキャッシュデータの再検証について詳しく学びましょう。 ## パターン {#patterns} -### 並列および逐次データ取得 {#parallel-and-sequential-data-fetching} +### 並行および逐次データ取得 {#parallel-and-sequential-data-fetching} -コンポーネント内でデータを取得する際には、並列および逐次の2つのデータ取得パターンを意識する必要があります。 +コンポーネント内でデータを取得するとき、2つのデータ取得パターンを意識する必要があります:並行と逐次。 順次および並列データ取得 -- **逐次**: コンポーネントtree内でリクエストが互いに依存している。この結果、読み込み時間が長くなることがあります -- **並列**: route内のリクエストが積極的に開始され、データは同時に読み込まれます。これにより、データの読み込みにかかる全体の時間が短縮されます +- **逐次**:コンポーネントツリー内のリクエストが互いに依存している場合。この場合、ロード時間が長くなる可能性があります。 +- **並行**:ルート内のリクエストが積極的に開始され、データが同時にロードされます。これにより、データをロードするための合計時間を短縮できます。 #### 逐次データ取得 {#sequential-data-fetching} -ネストされたコンポーネントがあり、各コンポーネントが独自にデータを取得する場合、これらのデータリクエストが[メモ化](/docs/app/building-your-application/caching#request-memoization)されていない場合、データ取得は逐次的に行われます。 +ネストされたコンポーネントがあり、各コンポーネントが独自のデータを取得する場合、これらのデータリクエストが[memoized](/docs/app/building-your-application/caching#request-memoization)されていない場合、データ取得は逐次的に行われます。 -このパターンが望ましい場合もあります。たとえば、`Playlists`コンポーネントは`Artist`コンポーネントがデータ取得を完了してからデータを取得し始めます。`Playlists`は`artistID` propに依存しているためです: +このパターンが有用である場合もあります。たとえば、1つの取得が他の取得の結果に依存している場合です。例えば、`Playlists`コンポーネントは`artistID` propに依存しているため、`Artist`コンポーネントがデータ取得を終了してから`Playlists`がデータ取得を開始します: ```tsx title="app/artist/[username]/page.tsx" switcher export default async function Page({ - params: { username }, + params, }: { params: Promise<{ username: string }> }) { - // アーティスト情報の取得 + const { username } = await params + // アーティスト情報を取得 const artist = await getArtist(username) return ( <>

              {artist.name}

              - {/* Playlistsコンポーネントの読み込み中にフォールバックUIを表示 */} + {/* プレイリストコンポーネントがロード中にフォールバックUIを表示 */} Loading...}> {/* アーティストIDをPlaylistsコンポーネントに渡す */} @@ -507,14 +512,15 @@ async function Playlists({ artistID }: { artistID: string }) { ```jsx title="app/artist/[username]/page.js" switcher -export default async function Page({ params: { username } }) { - // アーティスト情報の取得 +export default async function Page({ params }) { + const { username } = await params + // アーティスト情報を取得 const artist = await getArtist(username) return ( <>

              {artist.name}

              - {/* Playlistsコンポーネントの読み込み中にフォールバックUIを表示 */} + {/* プレイリストコンポーネントがロード中にフォールバックUIを表示 */} Loading...}> {/* アーティストIDをPlaylistsコンポーネントに渡す */} @@ -540,19 +546,19 @@ async function Playlists({ artistID }) {
              -[`loading.js`](/docs/app/building-your-application/routing/loading-ui-and-streaming)(routeセグメント用)または[React ``](/docs/app/building-your-application/routing/loading-ui-and-streaming#streaming-with-suspense)(ネストされたコンポーネント用)を使用して、即時の読み込み状態を表示することができます。 +[`loading.js`](/docs/app/building-your-application/routing/loading-ui-and-streaming)(ルートセグメント用)または[React ``](/docs/app/building-your-application/routing/loading-ui-and-streaming#streaming-with-suspense)(ネストされたコンポーネント用)を使用して、結果がストリームで送信される間、即座にロード状態を表示することができます; -これにより、データリクエストによってroute全体がブロックされるのを防ぎ、ユーザーは準備ができているページの部分と対話できるようになります。 +これにより、データリクエストによってルート全体がブロックされるのを防ぎ、準備の整ったページの部分にユーザーがインタラクトできるようになります。 -#### 並列データ取得 {#parallel-data-fetching} +#### 並行データ取得 {#parallel-data-fetching} -デフォルトで、レイアウトとページセグメントは並列にレンダリングされます。これにより、リクエストは並行して開始されます。 +デフォルトでは、レイアウトとページセグメントは並行してレンダリングされます;これにより要求が並行して開始されます; -しかし、`async`/`await`の特性上、同じセグメントまたはコンポーネント内で待たれるリクエストはそれ以下のリクエストをブロックします。 +しかし、`async`/`await`の特性のため,同じセグメントやコンポーネント内で待機されたリクエストはその下にあるリクエストをブロックします; -データを並列に取得するには、データを使用するコンポーネントの外側でリクエストを定義して積極的に開始します。これにより、両方のリクエストが並行して開始され時間を節約しますが、両方のプロミスが解決されるまでユーザーはレンダリングされた結果を目にすることはありません。 +データを並行して取得するには、データを使用するコンポーネントの外で要求を積極的に開始することができます;これにより、並行して両方の要求を始めることができますが、両方のプロミスが解決されるまでユーザーはレンダリング結果を表示できません; -下の例では、`getArtist`と`getAlbums`関数が`Page`コンポーネントの外側に定義され、コンポーネント内で`Promise.all`を使用して開始されます: +次の例では、`getArtist`と`getAlbums`関数が`Page`コンポーネントの外で定義され、`Promise.all`を使用してコンポーネント内で開始されています: @@ -571,14 +577,15 @@ async function getAlbums(username: string) { } export default async function Page({ - params: { username }, + params, }: { params: Promise<{ username: string }> }) { + const { username } = await params const artistData = getArtist(username) const albumsData = getAlbums(username) - // 両方のリクエストを並行して開始する + // 並行して両方のリクエストを開始 const [artist, albums] = await Promise.all([artistData, albumsData]) return ( @@ -606,11 +613,12 @@ async function getAlbums(username) { return res.json() } -export default async function Page({ params: { username } }) { +export default async function Page({ params }) { + const { username } = await params const artistData = getArtist(username) const albumsData = getAlbums(username) - // 両方のリクエストを並行して開始する + // 並行して両方のリクエストを開始 const [artist, albums] = await Promise.all([artistData, albumsData]) return ( @@ -625,13 +633,13 @@ export default async function Page({ params: { username } }) { -さらに、[Suspense Boundary](/docs/app/building-your-application/routing/loading-ui-and-streaming)を追加することで、レンダリング作業を分割し可能な限り早く部分的な結果を表示することができます。 +さらに、レンダリング作業を中断し、結果の一部をできるだけ早く表示するために、[Suspense Boundary](/docs/app/building-your-application/routing/loading-ui-and-streaming)を追加することができます; -### データの事前ロード {#preloading-data} +### データのプリロード {#preloading-data} -ウォーターフォールを防ぐもう1つの方法は、ユーティリティ関数を作成し、ブロッキングリクエストの上で積極的に呼び出す*preload*パターンを使用することです。たとえば、`checkIsAvailable()`は``のレンダリングをブロックするので、`preload()`をその前に呼び出して``のデータ依存関係を積極的に開始できます。``がレンダリングされるとき、そのデータはすでに取得されています。 +ウォーターフォールを防ぐもう1つの方法は、ユーティリティ関数を作成してブロッキングリクエストの上で積極的に呼び出すことで*preload*パターンを使用することです;例えば、`checkIsAvailable()`は``のレンダリングをブロックしますので、`preload()`をその前に呼び出して``データ依存関係を積極的に開始できます;``がレンダリングされるころには、そのデータはすでに取得されています; -なお、`preload`関数は`checkIsAvailable()`の実行をブロックしません。 +`preload`関数は`checkIsAvailable()`が実行されることをブロックしないことに注意してください。 @@ -640,7 +648,7 @@ export default async function Page({ params: { username } }) { import { getItem } from '@/utils/get-item' export const preload = (id: string) => { - // voidは指定された式を評価して未定義を返します。 + // void は与えられた式を評価し、undefinedを返します // https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/void void getItem(id) } @@ -657,7 +665,7 @@ export default async function Item({ id }: { id: string }) { import { getItem } from '@/utils/get-item' export const preload = (id) => { - // voidは指定された式を評価して未定義を返します。 + // void は与えられた式を評価し、undefinedを返します // https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/void void getItem(id) } @@ -677,13 +685,14 @@ export default async function Item({ id }) { import Item, { preload, checkIsAvailable } from '@/components/Item' export default async function Page({ - params: { id }, + params, }: { params: Promise<{ id: string }> }) { + const { id } = await params // アイテムデータの読み込みを開始 preload(id) - // 他の非同期タスクを実行 + // 別の非同期タスクを実行 const isAvailable = await checkIsAvailable() return isAvailable ? : null @@ -696,10 +705,11 @@ export default async function Page({ ```jsx title="app/item/[id]/page.js" switcher import Item, { preload, checkIsAvailable } from '@/components/Item' -export default async function Page({ params: { id } }) { +export default async function Page({ params }) { + const { id } = await params // アイテムデータの読み込みを開始 preload(id) - // 他の非同期タスクを実行 + // 別の非同期タスクを実行 const isAvailable = await checkIsAvailable() return isAvailable ? : null @@ -709,11 +719,11 @@ export default async function Page({ params: { id } }) { -> **Good to know:** "preload"関数はAPIではなくパターンであるため、任意の名前を持つことができます。 +> **Good to know:** 「preload」関数はパターンであってAPIではないため、どんな名前も持つことができます。 -#### Reactの`cache`と`server-only`を使用したPreloadパターン {#using-react-cache-and-server-only-with-the-preload-pattern} +#### Reactの`cache`と`server-only`を使用してPreloadパターンを実装する {#using-react-cache-and-server-only-with-the-preload-pattern} -`cache`関数、preloadパターン、`server-only`パッケージを組み合わせて、アプリ全体で使用可能なデータ取得ユーティリティを作成することができます。 +`cache`関数、`preload`パターン、`server-only`パッケージを組み合わせてアプリ全体で使用可能なデータ取得ユーティリティを作成できます。 @@ -750,19 +760,19 @@ export const getItem = cache(async (id) => { -このアプローチを使用すると、データを積極的に取得し、レスポンスをキャッシュし、このデータ取得が[サーバー上でのみ行われることを保証](/docs/app/building-your-application/rendering/composition-patterns#keeping-server-only-code-out-of-the-client-environment)することができます。 +このアプローチにより、データを積極的に取得し、レスポンスをキャッシュし、このデータ取得が[サーバーでのみ発生することを保証する](/docs/app/building-your-application/rendering/composition-patterns#keeping-server-only-code-out-of-the-client-environment)ことができます。 -`utils/get-item`エクスポートは、レイアウト、ページ、または他のコンポーネントによって使用され、アイテムのデータ取得のタイミングを制御することができます。 +`utils/get-item`エクスポートは、レイアウト、ページ、またはその他のコンポーネントで使用され、アイテムデータが取得されるタイミングを制御できます。 -> **Good to know:** +> **Good to know:** > -> - サーバー側のデータ取得関数がクライアントで使用されないことを確認するために、[`server-only`パッケージ](/docs/app/building-your-application/rendering/composition-patterns#keeping-server-only-code-out-of-the-client-environment)を使用することを推奨します。 +> - サーバーデータ取得関数がクライアントで使用されないことを保証するために、[`server-only`パッケージ](/docs/app/building-your-application/rendering/composition-patterns#keeping-server-only-code-out-of-the-client-environment)の使用を推奨します。 -### クライアントへの機密データの露出を防ぐ {#preventing-sensitive-data-from-being-exposed-to-the-client} +### クライアントに機密データが露出しないように防ぐ {#preventing-sensitive-data-from-being-exposed-to-the-client} -オブジェクトインスタンスや機密値全体がクライアントに渡されないようにするために、Reactの汚染API、[`taintObjectReference`](https://react.dev/reference/react/experimental_taintObjectReference)および[`taintUniqueValue`](https://react.dev/reference/react/experimental_taintUniqueValue)を使用することをお勧めします。 +Reactの汚染API、[`taintObjectReference`](https://react.dev/reference/react/experimental_taintObjectReference)や[`taintUniqueValue`](https://react.dev/reference/react/experimental_taintUniqueValue)を使用して、オブジェクト全体のインスタンスや機密の値がクライアントに渡されないようにすることをお勧めします。 -アプリケーションで汚染を有効にするには、Next.js Configの`experimental.taint`オプションを`true`に設定します: +あなたのアプリケーションで汚染を有効にするために、Next.js Configの`experimental.taint`オプションを`true`に設定します: ```js title="next.config.js" module.exports = { @@ -772,7 +782,7 @@ module.exports = { } ``` -次に、`experimental_taintObjectReference`または`experimental_taintUniqueValue`関数に渡したいオブジェクトまたは値を渡します: +次に`experimental_taintObjectReference`または`experimental_taintUniqueValue`関数に汚染したいオブジェクトや値を渡します: @@ -837,8 +847,8 @@ export async function Page() { const userData = getUserData() return ( ) } @@ -854,8 +864,8 @@ export async function Page() { const userData = await getUserData() return ( ) } diff --git a/docs/01-app/02-building-your-application/02-data-fetching/03-server-actions-and-mutations.mdx b/docs/01-app/02-building-your-application/02-data-fetching/03-server-actions-and-mutations.mdx index a998744..293cd7d 100644 --- a/docs/01-app/02-building-your-application/02-data-fetching/03-server-actions-and-mutations.mdx +++ b/docs/01-app/02-building-your-application/02-data-fetching/03-server-actions-and-mutations.mdx @@ -1,24 +1,24 @@ --- -title: 'Server Actions とデータ変更' -nav_title: 'Server Actions とデータ変更' -description: 'Next.jsを用いたフォーム送信とデータ変更の処理方法を学びましょう。' +title: 'Server Actionsと変化' +nav_title: 'Server Actionsと変化' +description: 'Next.jsでフォームの送信とデータの変化を処理する方法について学びます。' related: - description: 'Next.jsにおけるServer Actionsの設定方法を学びましょう' + description: 'Next.jsでServer Actionsを設定する方法を学びます' links: - app/api-reference/config/next-config-js/serverActions --- -[Server Actions](https://react.dev/reference/rsc/server-actions) は **非同期関数** であり、サーバー上で実行されます。これらはServerおよびClient Componentsの中で、Next.jsアプリケーションでのフォーム送信とデータの変更を管理するために呼び出すことができます。 +[Server Actions](https://react.dev/reference/rsc/server-actions)は、サーバー上で実行される**非同期関数**です。Next.jsアプリケーションでフォーム送信やデータの変化を処理するために、Server ComponentやClient Componentから呼び出すことができます。 -> **🎥 視聴:** Server Actions を用いたデータ変更について詳しく学びましょう → [YouTube (10 分)](https://youtu.be/dDpZfOQBMaU?si=cJZHlUu_jFhCzHUg)。 +> **🎥 視聴:** Server Actionsを使った変化について詳しく知る→ [YouTube (10分)](https://youtu.be/dDpZfOQBMaU?si=cJZHlUu_jFhCzHUg) ## 規約 {#convention} -Server Action はReactの[`"use server"`](https://react.dev/reference/react/use-server)ディレクティブを用いて定義できます。非同期関数の上部にディレクティブを置いて、関数をServer Actionとしてマークするか、別ファイルの上部にディレクティブを置いて、そのファイルのすべてのエクスポートをServer Actionとしてマークすることができます。 +Server ActionはReactの[`"use server"`](https://react.dev/reference/react/use-server)ディレクティブを使用して定義できます。このディレクティブを`async`関数の先頭に配置して、関数をServer Actionとしてマークするか、別ファイルの先頭に配置して、そのファイルのすべてのエクスポートをServer Actionとしてマークできます。 ### Server Components {#server-components} -Server Components は、インライン関数レベルまたはモジュールレベルで`"use server"`ディレクティブを使用できます。Server Actionをインラインで使うには、関数本体の上部に`"use server"`を追加してください: +Server Componentsは、インライン関数レベルまたはモジュールレベルで`"use server"`ディレクティブを使用できます。Server Actionをインラインで使用するには、関数本体の先頭に`"use server"`を追加します。 @@ -28,7 +28,7 @@ export default function Page() { // Server Action async function create() { 'use server' - // データを変更する + // データの変化 } return '...' @@ -43,7 +43,7 @@ export default function Page() { // Server Action async function create() { 'use server' - // データを変更する + // データの変化 } return '...' @@ -55,7 +55,7 @@ export default function Page() { ### Client Components {#client-components} -Client ComponentでServer Actionを呼び出すには、新しいファイルを作成して、その上部に「use server」ディレクティブを追加します。そのファイル内でエクスポートされるすべての関数が、ClientとServer Componentの両方で再利用可能なServer Actionとしてマークされます。 +Client ComponentでServer Actionを呼び出すためには、新しいファイルを作成し、そのトップに`"use server"`ディレクティブを追加します。ファイル内のすべてのエクスポートされた関数は、Client ComponentとServer Componentの両方で再利用できるServer Actionとしてマークされます。 @@ -107,9 +107,9 @@ export function Button() { -### アクションを props として渡す {#passing-actions-as-props} +### Propとしてアクションを渡す {#passing-actions-as-props} -Server Action を Client Component に props として渡すこともできます: +Server ActionをpropとしてClient Componentに渡すこともできます。 ```jsx @@ -144,29 +144,29 @@ export default function ClientComponent({ updateItemAction }) { -通常、Next.js TypeScriptプラグインは `client-component.tsx` の `updateItemAction` を警告しますが、これは一般にクライアント側とサーバー側の境界を越えてシリアル化できない関数だからです。しかし、`action` として名前付けされた props または `Action` で終了する props は Server Actions を受け取ることが想定されています。これはあくまでヒューリスティックであり、TypeScriptプラグインは実際に Server Action を受け取っているか、通常の関数を受け取っているかはわかりません。ランタイム型チェックにより、間違って関数をClient Componentに渡さないようにします。 +通常、Next.js TypeScriptプラグインは、`client-component.tsx`内の`updateItemAction`をフラグします。これは通常、クライアント-サーバー境界を越えて直列化できない関数であるためです。しかし、`action`という名前または`Action`で終わる名前のpropは、Server Actionを受け取ると想定されます。これは推論に過ぎず、TypeScriptプラグインがServer Actionまたは通常の関数を受け取っているかどうかは実際には知りません。実行時の型チェックにより、誤ってClient Componentに関数を渡さないようにします。 -## 行動 {#behavior} +## 動作 {#behavior} -- Server actionは、[`
              `要素](#forms) の `action` 属性を使用して呼び出すことができます: - - Server Componentsはデフォルトでプログレッシブエンハンスメントをサポートしており、JavaScriptがまだ読み込まれていない場合や無効になっている場合でもフォームが送信されます。 - - Client Componentsでは、JavaScriptがまだ読み込まれていない場合、Server Actions を呼び出すフォームは送信をキューに入れ、クライアントのハイドレーションを優先します。 - - ハイドレーション後、ブラウザはフォーム送信時にリフレッシュしません。 -- Server Actionsは``に限定されず、イベントハンドラ、`useEffect`、サードパーティのライブラリ、`
              - {/* Works, since Carousel is used within a Client Component */} + {/* クライアントコンポーネント内で使用しているため機能します */} {isOpen && } ) @@ -158,7 +158,7 @@ export default function Gallery() {
              - {/* Works, since Carousel is used within a Client Component */} + {/* クライアントコンポーネント内で使用しているため機能します */} {isOpen && }
              ) @@ -168,7 +168,7 @@ export default function Gallery() {
              -しかし、Server Component内で直接使用しようとすると、エラーが表示されます: +しかし、サーバーコンポーネント内で直接使用しようとすると、エラーが表示されます: @@ -181,7 +181,7 @@ export default function Page() {

              View pictures

              - {/* Error: `useState` can not be used within Server Components */} + {/* エラー: `useState` はサーバーコンポーネント内で使用できません */}
              ) @@ -199,7 +199,7 @@ export default function Page() {

              View pictures

              - {/* Error: `useState` can not be used within Server Components */} + {/* エラー: `useState` はサーバーコンポーネント内で使用できません */}
              ) @@ -209,9 +209,9 @@ export default function Page() {
              -これはNext.jsが``がクライアント専用の機能を使用していることを知らないためです。 +これは Next.js が `` がクライアント専用の機能を使用していることを知らないためです。 -これを修正するために、クライアント専用の機能に依存するサードパーティコンポーネントを自分のClient Componentsでラップすることができます: +これを修正するには、クライアント専用機能に依存するサードパーティコンポーネントを独自のクライアントコンポーネントでラップします: @@ -238,7 +238,7 @@ export default Carousel -これで、Server Component内で直接``を使用することができます: +これで、サーバーコンポーネント内で `` を直接使用できます: @@ -251,7 +251,7 @@ export default function Page() {

              View pictures

              - {/* Works, since Carousel is a Client Component */} + {/* クライアントコンポーネントであるため機能します */}
              ) @@ -269,7 +269,7 @@ export default function Page() {

              View pictures

              - {/* Works, since Carousel is a Client Component */} + {/* クライアントコンポーネントであるため機能します */}
              ) @@ -279,11 +279,11 @@ export default function Page() {
              -私たちは、ほとんどのサードパーティコンポーネントをラップする必要はないと考えています。なぜなら、それらをClient Components内で使用することが多いためです。しかし、例外はプロバイダーです。プロバイダーはReactの状態とコンテキストに依存しており、典型的にはアプリケーションのrootで必要とされるためです。[以下でサードパーティのコンテキストプロバイダーについて詳しく学びましょう](#using-context-providers)。 +ほとんどのサードパーティコンポーネントをラップする必要はないと予想していますが、例外はプロバイダーです。プロバイダーは React の状態とコンテキストに依存しており、通常アプリケーションの root で必要です。サードパーティのコンテキストプロバイダーについては[さらに詳しく学ぶ](#using-context-providers)。 #### コンテキストプロバイダーの使用 {#using-context-providers} -コンテキストプロバイダーは通常、アプリケーションのroot付近でレンダリングされ、現在のテーマなどのグローバルな問題を共有します。[React コンテキスト](https://react.dev/learn/passing-data-deeply-with-context)はServer Componentsではサポートされていないため、アプリケーションのrootでコンテキストを作成しようとするとエラーが発生します: +コンテキストプロバイダーは、アプリケーションの root 近くで、現在のテーマなどのグローバルな問題を共有するためにレンダリングされることがよくあります。[React コンテキスト](https://react.dev/learn/passing-data-deeply-with-context) はサーバーコンポーネントではサポートされていないため、アプリケーションの root でコンテキストを作成しようとするとエラーが発生します: @@ -291,10 +291,14 @@ export default function Page() { ```tsx title="app/layout.tsx" switcher import { createContext } from 'react' -// createContext is not supported in Server Components +// createContext はサーバーコンポーネントではサポートされていません export const ThemeContext = createContext({}) -export default function RootLayout({ children }) { +export default function RootLayout({ + children, +}: { + children: React.ReactNode +}) { return ( @@ -311,7 +315,7 @@ export default function RootLayout({ children }) { ```jsx title="app/layout.js" switcher import { createContext } from 'react' -// createContext is not supported in Server Components +// createContext はサーバーコンポーネントではサポートされていません export const ThemeContext = createContext({}) export default function RootLayout({ children }) { @@ -328,7 +332,7 @@ export default function RootLayout({ children }) { -これを解決するためには、コンテキストを作成し、そのプロバイダーをClient Component内にレンダリングします: +これを修正するには、クライアントコンポーネント内でコンテキストを作成し、そのプロバイダーをレンダリングします: @@ -367,7 +371,7 @@ export default function ThemeProvider({ children }) { -Server ComponentはプロバイダーがClient Componentとしてマークされたので、直接レンダリングできます: +サーバーコンポーネントは、クライアントコンポーネントとしてマークされたプロバイダーを直接レンダリングできるようになります: @@ -410,38 +414,38 @@ export default function RootLayout({ children }) { -プロバイダーがrootにレンダリングされることで、アプリ全体の他のClient Componentsは、このコンテキストを利用できます。 +プロバイダーは root にレンダリングされるため、アプリ全体の他のクライアントコンポーネントはこのコンテキストを消費できます。 -> **Good to know**: プロバイダーはできるだけ深い位置にレンダリングするべきです。 `ThemeProvider`が、HTMLドキュメント全体ではなく `{children}` のみをラップしている点に注目してください。これにより、Next.jsはServer Componentsの静的な部分を最適化しやすくなります。 +> **Good to know**: プロバイダーは tree の中できるだけ深くレンダリングするべきです。`ThemeProvider` が `{children}` のみをラップし、`` 全体をラップしていないことに注意してください。これにより、Next.js がサーバーコンポーネントの静的部分を最適化しやすくなります。 -#### ライブラリアー作者へのアドバイス {#advice-for-library-authors} +#### ライブラリ作者へのアドバイス {#advice-for-library-authors} -同様に、他の開発者に消費されるパッケージを作成しているライブラリアー作者は、パッケージのクライアントエントリーポイントをマークするために`"use client"`ディレクティブを使用できます。これにより、パッケージユーザーはServer Componentsにパッケージコンポーネントを直接インポートし、ラッピング境界を作成する必要がなくなります。 +同様に、他の開発者が使用するためのパッケージを作成するライブラリの作者は、`"use client"` ディレクティブを使用してパッケージのクライアントエントリポイントをマークすることができます。これにより、パッケージのユーザーは、ラッピング境界を作成することなく、サーバーコンポーネントにパッケージコンポーネントを直接インポートできます。 -モジュールをServer Componentのモジュールグラフの一部に含めることを可能にするためには、['use client' をツリーの深い場所で使用して](#moving-client-components-down-the-tree)、パッケージを最適化できます。 +インポートされたモジュールをサーバーコンポーネントのモジュールグラフの一部にするために、package 内で 'use client' を [tree の奥深くに移動させる](#moving-client-components-down-the-tree) ことによってパッケージを最適化できるでしょう。 -一部のバンドラは`"use client"`ディレクティブを削除することがあります。`React Wrap Balancer`や`Vercel Analytics`リポジトリで[esbuildを設定する例](https://github.com/shuding/react-wrap-balancer/blob/main/tsup.config.ts#L10-L13)を見つけることができます。 +一部のバンドラーは `"use client"` の指令を除去するかもしれません。[React Wrap Balancer](https://github.com/shuding/react-wrap-balancer/blob/main/tsup.config.ts#L10-L13) や [Vercel Analytics](https://github.com/vercel/analytics/blob/main/packages/web/tsup.config.js#L26-L30) のリポジトリで、`esbuild` を `"use client"` 指令を含めるように設定する例を見ることができます。 -## Client Components {#client-components} +## クライアントコンポーネント {#client-components} -### Client Componentsをツリーの深い場所に移動する {#moving-client-components-down-the-tree} +### クライアントコンポーネントを tree の奥深くに移動 {#moving-client-components-down-the-tree} -Client JavaScriptのバンドルサイズを削減するため、Client Componentsをコンポーネントツリーの下位に移動することをお勧めします。 +クライアント JavaScript バンドルのサイズを削減するために、クライアントコンポーネントをコンポーネント tree の奥深くに移動することをお勧めします。 -例えば、静的な要素(ロゴ、リンクなど)とstateを使用するインタラクティブな検索バーを含むレイアウトがあるかもしれません。 +たとえば、静的な要素(ロゴやリンクなど)を持ち、状態を使用しているインタラクティブな検索バーがあるレイアウトがあるかもしれません。 -レイアウト全体をClient Componentにする代わりに、インタラクティブなロジックをClient Component(例:``)に移動し、レイアウトをServer Componentとして保持します。これにより、レイアウトのすべてのコンポーネントJavaScriptをクライアントに送信する必要がなくなります。 +レイアウト全体をクライアントコンポーネントにする代わりに、インタラクティブなロジックをクライアントコンポーネント(例:``)に移動し、レイアウトをサーバーコンポーネントとして保持します。これにより、レイアウトのすべてのコンポーネント JavaScript をクライアントに送信する必要がなくなります。 ```tsx title="app/layout.tsx" switcher -// SearchBar is a Client Component +// SearchBarはクライアントコンポーネントです import SearchBar from './searchbar' -// Logo is a Server Component +// Logoはサーバーコンポーネントです import Logo from './logo' -// Layout is a Server Component by default +// Layoutはデフォルトでサーバーコンポーネントです export default function Layout({ children }: { children: React.ReactNode }) { return ( <> @@ -459,12 +463,12 @@ export default function Layout({ children }: { children: React.ReactNode }) { ```jsx title="app/layout.js" switcher -// SearchBar is a Client Component +// SearchBar はクライアントコンポーネントです import SearchBar from './searchbar' -// Logo is a Server Component +// Logo はサーバーコンポーネントです import Logo from './logo' -// Layout is a Server Component by default +// Layout はデフォルトでサーバーコンポーネントです export default function Layout({ children }) { return ( <> @@ -481,38 +485,39 @@ export default function Layout({ children }) { -### ServerからClient Componentsにpropsを渡す(シリアライズ) {#passing-props-from-server-to-client-components-serialization} +### Server から Client Components への props の受け渡し(シリアル化) {#passing-props-from-server-to-client-components-serialization} -Server Componentでデータを取得した場合、それをClient Componentにpropsとして渡すことを望むかもしれません。ServerからClient Componentsに渡されるpropsはReactによって[シリアライズ可能](https://react.dev/reference/react/use-server#serializable-parameters-and-return-values)である必要があります。 +サーバーコンポーネントでデータを取得した場合、データを props としてクライアントコンポーネントに渡すことができます。Server から Client Components に渡される props は React によって [シリアル化可能](https://react.dev/reference/react/use-server#serializable-parameters-and-return-values) である必要があります。 -Client Componentsがシリアライズできないデータに依存している場合は、[サードパーティライブラリを使用してクライアントでデータを取得](https://nextjs.org/docs/app/building-your-application/data-fetching/fetching#fetching-data-on-the-client)するか、[Route Handler](https://nextjs.org/docs/app/building-your-application/routing/route-handlers)を使用してサーバーでデータを取得することができます。 +クライアントコンポーネントがシリアル化されていないデータに依存している場合、[サードパーティのライブラリを使用してクライアントでデータを取得](https://nextjs.org/docs/app/building-your-application/data-fetching/fetching#fetching-data-on-the-client)するか、[Route Handler](https://nextjs.org/docs/app/building-your-application/routing/route-handlers)でサーバーでフェッチすることが可能です。 -## ServerとClient Componentsのインターレース {#interleaving-server-and-client-components} +## Server と Client Components の組み合わせ {#interleaving-server-and-client-components} -Client ComponentsとServer Componentsを交互に使用する際には、UIをコンポーネントのツリーとして視覚化すると役立つ場合があります。[root レイアウト](https://nextjs.org/docs/app/building-your-application/routing/layouts-and-templates#root-layout-required)はServer Componentで始まり、その後`"use client"`ディレクティブを追加することで、クライアント上で特定のコンポーネントサブツリーをレンダリングすることができます。 +Client と Server Components を組み合わせる際、UI をコンポーネントの tree として視覚化すると役立ちます。[root レイアウト](/docs/app/building-your-application/routing/layouts-and-templates#root-layout-required)(サーバーコンポーネント)から始めて、`"use client"` 指令を追加することにより、コンポーネントの特定のサブ tree をクライアントでレンダリングできます。 -{/* Diagram - interleaving */} +{/* 図 - インターレイビング */} -これらのクライアントサブツリー内では、依然としてServer Componentsをネストしたり、Server Actionsを呼び出したりすることは可能ですが、考慮すべき点があります。 +そのクライアントサブ tree 内で、依然としてサーバーコンポーネントをネストしたり、サーバーアクションを呼び出したりすることができますが、以下の点に留意してください: -- リクエスト-レスポンスライフサイクル中に、コードはサーバーからクライアントに移動します。クライアント上でサーバー上のデータやリソースにアクセスする必要がある場合は、新しいリクエストがサーバーに送られます。切り替えるのではなく、行き来することはありません -- 新しいリクエストがサーバーに送られると、すべてのServer Componentが最初にレンダリングされ、Client Component内にネストされているものも含まれます。レンダリングされた結果([RSCペイロード](https://nextjs.org/docs/app/building-your-application/rendering/server-components#what-is-the-react-server-component-payload-rsc))には、Client Componentsの場所への参照が含まれます。その後、クライアント上でReactはこのRSCペイロードを使ってServerとClient Componentsを統合し、1つのツリーにします +- リクエスト-レスポンスライフサイクル中、コードはサーバーからクライアントに移動します。クライアント上でサーバー上のデータやリソースにアクセスする必要がある場合、サーバーへの**新しい**リクエストを行うことになります - 行ったり来たりすることはありません。 +- 新しいリクエストがサーバーに送信されると、全てのサーバーコンポーネントが最初にレンダリングされます。その中には、クライアントコンポーネント内にネストされているものも含まれます。レンダリングの結果([RSC Payload](/docs/app/building-your-application/rendering/server-components#what-is-the-react-server-component-payload-rsc))には、クライアントコンポーネントの位置への参照が含まれます。次に、クライアントで、React は RSC ペイロードを使用して、サーバーコンポーネントとクライアントコンポーネントを一つの tree に統合します。 -{/* Diagram */} +{/* 図 */} -- Client ComponentsはServer Componentsの後にレンダリングされるため、Server ComponentをClient Componentモジュール内にインポートすることはできません(新しいリクエストでサーバーに戻る必要があります)。代わりに、Server ComponentをpropsとしてClient Componentに渡すことができます。[サポートされていないパターン](#unsupported-pattern-importing-server-components-into-client-components)と[サポートされているパターン](#supported-pattern-passing-server-components-to-client-components-as-props)のセクションを参照してください。 +- Client Components はサーバーコンポーネントの後にレンダリングされるため、クライアントコンポーネントモジュールにサーバーコンポーネントをインポートすることはできません(新たなリクエストを再びサーバーに送り返す必要があるため)。代わりに、Server コンポーネントを Client Component の `props` として渡すことができます。以下の[非推奨のパターン](#unsupported-pattern-importing-server-components-into-client-components)と[サポートされているパターン](#supported-pattern-passing-server-components-to-client-components-as-props)を参照してください。 -### サポートされていないパターン:Server ComponentsをClient Componentsにインポートする {#unsupported-pattern-importing-server-components-into-client-components} +### 非サポートパターン:Server コンポーネントをクライアントコンポーネントにインポート {#unsupported-pattern-importing-server-components-into-client-components} -以下のパターンはサポートされていません。Client ComponentにServer Componentをインポートすることはできません: +以下のパターンはサポートされていません。Server コンポーネントを Client コンポーネントにインポートすることはできません: -```tsx title="app/client-component.tsx" highlight={3,4,17} switcher +```tsx title="app/client-component.tsx" switcher +highlight={3,4,17} 'use client' -// You cannot import a Server Component into a Client Component. +// Server コンポーネントを Client コンポーネントにインポートすることはできません。 import ServerComponent from './Server-Component' export default function ClientComponent({ @@ -535,10 +540,11 @@ export default function ClientComponent({ -```jsx title="app/client-component.js" highlight={3,13} switcher +```jsx title="app/client-component.js" switcher +highlight={3,13} 'use client' -// You cannot import a Server Component into a Client Component. +// Server コンポーネントを Client コンポーネントにインポートすることはできません。 import ServerComponent from './Server-Component' export default function ClientComponent({ children }) { @@ -557,18 +563,19 @@ export default function ClientComponent({ children }) { -### サポートされているパターン:Server ComponentsをClient Componentsにpropsとして渡す {#supported-pattern-passing-server-components-to-client-components-as-props} +### サポートされているパターン:Server コンポーネントをクライアントコンポーネントに props として渡すこと {#supported-pattern-passing-server-components-to-client-components-as-props} -以下のパターンはサポートされています。Server ComponentsをpropsとしてClient Componentに渡すことができます。 +次のパターンはサポートされています。サーバーコンポーネントをクライアントコンポーネントの prop として渡すことができます。 -一般的なパターンは、`children` propを使用して、Client Componentに*"スロット"*を作成することです。 +よくあるパターンとして、React の `children` prop を使用してクライアントコンポーネント内でスロットを作成する方法があります。 -以下の例では、``が`children` propを受け入れます: +以下の例では、`` は `children` prop を受け入れます: -```tsx title="app/client-component.tsx" highlight={6,15} switcher +```tsx title="app/client-component.tsx" switcher +highlight={6,15} 'use client' import { useState } from 'react' @@ -592,7 +599,8 @@ export default function ClientComponent({ -```jsx title="app/client-component.js" highlight={5,12} switcher +```jsx title="app/client-component.js" switcher +highlight={5,12} 'use client' import { useState } from 'react' @@ -613,21 +621,20 @@ export default function ClientComponent({ children }) { -``は、`children`が最終的にServer Componentの結果で満たされることを知りません。``の唯一の責任は、`children`をどこに配置するかを決定することです。 +`` は `children` が最終的にサーバーコンポーネントの結果によって埋められることを知りません。`` の唯一の責任は、`children` が最終的に**どこに**配置されるかを決定することです。 -親Server Componentで、``と``の両方をインポートし、``を``の子として渡すことができます: +親のサーバーコンポーネントで、`` と `` の両方をインポートし、`` を `` の子として渡すことができます: ```tsx title="app/page.tsx" highlight={11} switcher -// This pattern works: -// You can pass a Server Component as a child or prop of a -// Client Component. +// このパターンは機能します: +// サーバーコンポーネントをクライアントコンポーネントの子や prop として渡すことができます。 import ClientComponent from './client-component' import ServerComponent from './server-component' -// Pages in Next.js are Server Components by default +// Next.js のページはデフォルトでサーバーコンポーネントです export default function Page() { return ( @@ -641,13 +648,12 @@ export default function Page() { ```jsx title="app/page.js" highlight={11} switcher -// This pattern works: -// You can pass a Server Component as a child or prop of a -// Client Component. +// このパターンは機能します: +// サーバーコンポーネントをクライアントコンポーネントの子や prop として渡すことができます。 import ClientComponent from './client-component' import ServerComponent from './server-component' -// Pages in Next.js are Server Components by default +// Next.js のページはデフォルトでサーバーコンポーネントです export default function Page() { return ( @@ -660,9 +666,9 @@ export default function Page() { -このアプローチでは、``と``は独立してレンダリングされることができ、``はクライアント上の``がレンダリングされる前に、サーバー上でレンダリングされます。 +このアプローチを使用すると、`` と `` がデカップルされ、独立してレンダリングされることが可能です。このケースでは、子の `` はサーバーにレンダリングすることが可能で、`` がクライアントにレンダリングされるはるか前に行われます。 > **Good to know:** > -> - 再レンダリングされるときにネストされた子コンポーネントが再レンダリングされないようにするために、"コンテンツを持ち上げる"パターンが使用されてきました -> - `children` propに限定されません。任意のpropを使用してJSXを渡すことができます +> - 親コンポーネントが再レンダリングされるときにネストされた子コンポーネントを再レンダリングすることを避けるために、「コンテンツを上に持ち上げる」パターンが使用されてきました。 +> - `children` prop に限定されません。任意の prop を使用して JSX を渡すことができます。 diff --git a/docs/01-app/02-building-your-application/04-caching/index.mdx b/docs/01-app/02-building-your-application/04-caching/index.mdx index b024cc7..c72f1ca 100644 --- a/docs/01-app/02-building-your-application/04-caching/index.mdx +++ b/docs/01-app/02-building-your-application/04-caching/index.mdx @@ -1,64 +1,64 @@ --- -title: 'Next.jsのキャッシュ' +title: 'Next.jsにおけるキャッシュ' nav_title: 'キャッシュ' -description: 'Next.jsにおけるキャッシングメカニズムの概要。' +description: 'Next.jsのキャッシュメカニズムの概要。' --- -Next.jsは、レンダリング作業やデータリクエストをキャッシュすることで、アプリケーションのパフォーマンスを向上させ、コストを削減します。このページでは、Next.jsのキャッシングメカニズム、またそれらを設定するために使用できるAPI、およびそれらがどのように相互作用するかについて詳しく説明します。 +Next.jsはレンダリング作業とデータリクエストをキャッシュすることで、アプリケーションのパフォーマンスを向上させ、コストを削減します。このページでは、Next.jsのキャッシュメカニズム、設定に使用できるAPI、およびそれらがどのように相互作用するかについて詳しく説明します。 -> **Good to know**: このページは、Next.jsが内部でどのように動作しているかを理解するのに役立ちますが、Next.jsを生産的に使用するための必須知識ではありません。ほとんどのNext.jsのキャッシングに関するユーリスティックは、APIの使用に基づいて決定され、最小限の設定で最高のパフォーマンスを発揮するためのデフォルトが設定されています。例を見たい場合は、[こちらから始めてください](/docs/app/building-your-application/data-fetching/fetching)。 +> **Good to know**: このページはNext.jsの内部がどのように機能しているかを理解するのに役立ちますが、Next.jsで生産的に稼働するために必ずしも必要な知識ではありません。Next.jsのキャッシュアルゴリズムの多くは、APIの使用方法に基づいて決定され、そのほとんどの場合はゼロまたは最小限の設定で最高のパフォーマンスのためのデフォルトが用意されています。代わりに、例をすぐに見たい場合は、[こちらから始めてください](/docs/app/building-your-application/data-fetching/fetching)。 ## 概要 {#overview} -以下は、さまざまなキャッシングメカニズムとその目的に関する高レベルの概要です: +次に、さまざまなキャッシュメカニズムとその目的の概要を示します: -| メカニズム | 内容 | 場所 | 目的 | 期間 | -| ------------------------------------------- | ------------------- | ------------ | ---------------------------------------------------------- | ------------------------------------ | -| [Request Memoization](#request-memoization) | 関数の戻り値 | サーバー | React Component treeでデータを再利用するため | リクエストライフサイクル中 | -| [Data Cache](#data-cache) | データ | サーバー | ユーザーリクエストやデプロイメント間でデータを保持 | 永続的(再検証可能) | -| [Full Route Cache](#full-route-cache) | HTMLとRSCペイロード | サーバー | レンダリングコストを削減し、パフォーマンスを向上させるため | 永続的(再検証可能) | -| [Router Cache](#client-side-router-cache) | RSCペイロード | クライアント | ナビゲーション時のサーバーリクエストを削減するため | ユーザーセッションまたは時間に基づく | +| メカニズム | 内容 | 場所 | 目的 | 期間 | +| ------------------------------------------- | ------------------- | ------------ | ------------------------------------------------------ | ---------------------------------- | +| [Request Memoization](#request-memoization) | 関数の戻り値 | サーバー | React Component tree内でデータを再利用する | リクエストライフサイクルごと | +| [Data Cache](#data-cache) | データ | サーバー | ユーザーリクエストとデプロイメント間でデータを保存する | 永続的(再検証可能) | +| [Full Route Cache](#full-route-cache) | HTMLとRSCペイロード | サーバー | レンダリングコストを削減し、パフォーマンスを向上させる | 永続的(再検証可能) | +| [Router Cache](#client-side-router-cache) | RSCペイロード | クライアント | ナビゲーション時のサーバーリクエストを削減する | ユーザーセッションまたは時間ベース | -Next.jsは、デフォルトでパフォーマンスを向上させコストを削減するために、できる限り多くのキャッシュを行います。つまり、ルートは**静的にレンダリング**され、データリクエストは**キャッシュ**されますが、これは任意で無効にできます。以下のダイアグラムは、ビルド時にルートが静的にレンダリングされるおよび静的なルートが最初に訪れられたときのデフォルトのキャッシング動作を示しています。 +デフォルトでは、Next.jsはパフォーマンスを向上させ、コストを削減するために可能な限り多くのキャッシュを行います。つまり、ルートは**静的にレンダリングされ**、データリクエストは**キャッシュされ**ますが、これをオプトアウトすることもできます。以下の図は、ビルド時と静的なルートが初めて訪問されたときにルートが静的にレンダリングされるときのデフォルトのキャッシュ動作を示しています: Next.jsのデフォルトキャッシング動作を示す図で、ビルド時と最初の訪問時のHIT、MISS、SETを示しています。 -キャッシング動作は、ルートが静的か動的か、データがキャッシュされているかされていないか、リクエストが初回訪問の一部なのか後続のナビゲーションによるものかによって変わります。ユースケースに応じて、個々のルートやデータリクエストのキャッシング動作を設定することができます。 +キャッシュ動作は、ルートが静的にレンダリングされるか動的にレンダリングされるか、データがキャッシュされているかされていないか、リクエストが初めての訪問か後続のナビゲーションの一部であるかによって変わります。ユースケースに応じて、個々のルートやデータリクエストのキャッシュ動作を設定することができます。 -## リクエストメモ化 {#request-memoization} +## Request Memoization {#request-memoization} -Reactは、同じURLとオプションを持つリクエストを自動的に**メモ化**するために[`fetch` API](#fetch)を拡張しています。これにより、Reactコンポーネントtree内の複数の場所で同じデータを取得するためのfetch関数を呼び出すことができますが、実行されるのは1度だけです。 +Reactは同じURLとオプションのリクエストを自動的に**メモ化**するために、[`fetch` API](#fetch)を拡張しています。これにより、Reactコンポーネントツリーの複数の場所で同じデータを取得するためのfetch関数を呼び出すことができますが、実行されるのは1回だけです。 重複排除されたFetchリクエスト -例えば、ルート全体で同じデータが必要な場合(例えば、Layout、Page、および複数のコンポーネントにおいて)、treeの最上部でデータをfetchし、コンポーネント間でpropsを転送する必要はありません。その代わりに、必要なコンポーネント内でデータを取得でき、同じデータに対するネットワーク上での複数リクエストのパフォーマンスへの影響を心配する必要はありません。 +たとえば、ルート全体で同じデータを使用する必要がある場合(例:レイアウト、ページ、および複数のコンポーネント)、ツリーの最上位でデータをフェッチし、それをコンポーネント間でpropsとして渡す必要はありません。代わりに、それを必要とするコンポーネントでデータをフェッチすることができ、同じデータに対してネットワークを介して複数のリクエストを行うことによるパフォーマンスへの影響を心配する必要はありません。 ```tsx title="app/example.tsx" switcher async function getItem() { - // `fetch`関数は自動的にメモ化され、その結果はキャッシュされます + // `fetch`関数は自動的にメモ化され、結果はキャッシュされます const res = await fetch('https://.../item/1') return res.json() } -// この関数は2回呼び出されますが、最初の1回のみ実行されます +// この関数は2回呼ばれるが、最初に実行されたときだけ実行されます const item = await getItem() // cache MISS -// 二度目の呼び出しはルート内のどこでも可能です +// 2番目の呼び出しはルート内のどこにでも配置できます const item = await getItem() // cache HIT ``` @@ -67,229 +67,229 @@ const item = await getItem() // cache HIT ```jsx title="app/example.js" switcher async function getItem() { - // `fetch`関数は自動的にメモ化され、その結果はキャッシュされます + // `fetch`関数は自動的にメモ化され、結果はキャッシュされます const res = await fetch('https://.../item/1') return res.json() } -// この関数は2回呼び出されますが、最初の1回のみ実行されます +// この関数は2回呼ばれるが、最初に実行されたときだけ実行されます const item = await getItem() // cache MISS -// 二度目の呼び出しはルート内のどこでも可能です +// 2番目の呼び出しはルート内のどこにでも配置できます const item = await getItem() // cache HIT ``` -**リクエストメモ化の仕組み** +**Request Memoizationの仕組み** Reactレンダリング中にfetchメモ化がどのように機能するかを示すダイアグラム。 -- ルートをレンダリングする際に、特定のリクエストが初めて呼び出されたとき、その結果はメモリに存在せず、キャッシュの`MISS`となります。 -- したがって、関数が実行され、データが外部ソースから取得され、その結果がメモリに格納されます。 -- 同じレンダーパス内でのリクエストの後続の関数呼び出しはキャッシュの`HIT`となり、関数を実行することなくメモリからデータが返されます。 -- ルートがレンダリングされ、レンダリングパスが完了すると、メモリは「リセット」され、すべてのリクエストメモ化エントリがクリアされます。 +- ルートをレンダリング中、特定のリクエストが最初に呼び出されたとき、その結果はメモリに存在せず、キャッシュ`MISS`になります。 +- そのため、関数が実行され、外部ソースからデータが取得され、その結果がメモリに保存されます。 +- 同じレンダリングパス内でのリクエストの後続の関数呼び出しはキャッシュ`HIT`となり、関数を実行せずにメモリからデータが返されます。 +- ルートがレンダリングされ、レンダリングパスが完了すると、メモリは「リセット」され、すべてのrequest memoizationエントリがクリアされます。 > **Good to know**: > -> - リクエストメモ化はReactの機能であり、Next.jsの機能ではありません。ここでは、他のキャッシングメカニズムとの相互作用を示すために含まれています。 -> - メモ化は`fetch`リクエストの`GET`メソッドにのみ適用されます。 -> - メモ化はReact Component treeにのみ適用されます。つまり: -> - `generateMetadata`、`generateStaticParams`、Layouts、Pages、およびその他のServer Components内の`fetch`リクエストに適用されます。 -> - Route Handlers内の`fetch`リクエストには適用されません。なぜなら、それらはReact component treeの一部ではないからです。 -> - `fetch`が適さない場合(例:一部のデータベースクライアント、CMSクライアント、GraphQLクライアント)、関数をメモ化するために[Reactの`cache`関数](#react-cache-function)を使用できます。 +> - Request memoizationはReactの機能であり、Next.jsの機能ではありません。ここに含めたのは、他のキャッシュメカニズムとの相互作用を示すためです。 +> - メモ化は、`fetch`リクエストの`GET`メソッドにのみ適用されます。 +> - メモ化は、React Component treeにのみ適用されます。つまり: +> - `generateMetadata`、`generateStaticParams`、レイアウト、ページ、およびその他のServer Componentsでの`fetch`リクエストに適用されます。 +> - Route Handlersでの`fetch`リクエストには適用されません。これらはReact component treeの一部ではないためです。 +> - `fetch`が適していない場合(例:一部のデータベースクライアント、CMSクライアント、またはGraphQLクライアント)、[React `cache`関数](#react-cache-function)を使用して関数をメモ化することができます。 ### 期間 {#duration} -キャッシュはサーバーリクエストのライフタイムが続く間、つまりReact component treeのレンダリングが完了するまで持続します。 +キャッシュはサーバーリクエストのライフタイムの間に存在し、React component treeのレンダリングが完了するまで続きます。 ### 再検証 {#revalidating} -メモ化はサーバーリクエスト間で共有されず、レンダリング中のみに適用されるため、再検証する必要はありません。 +メモ化はサーバーリクエスト間で共有されず、レンダリング中にのみ適用されるので、再検証の必要はありません。 ### オプトアウト {#opting-out} -メモ化は`fetch`リクエストの`GET`メソッドにのみ適用され、`POST`や`DELETE`などの他のメソッドはメモ化されません。このデフォルトの動作はReactの最適化であり、オプトアウトすることをお勧めしません。 +メモ化は、`fetch`リクエストの`GET`メソッドにのみ適用され、`POST`や`DELETE`などの他のメソッドはメモ化されません。このデフォルトの動作はReactの最適化であり、それをオプトアウトすることは推奨しません。 -個々のリクエストを管理するには、[`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController)の[`signal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController/signal)プロパティを使用できます。ただし、これはメモ化からオプトアウトするのではなく、実行中のリクエストを中止するものです。 +個々のリクエストを管理するには、[`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController)の[`signal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController/signal)プロパティを使用できます。しかし、これはメモ化からリクエストをオプトアウトするのではなく、実行中のリクエストを中止します。 ```js title="app/example.js" const { signal } = new AbortController() fetch(url, { signal }) ``` -## データキャッシュ {#data-cache} +## Data Cache {#data-cache} -Next.jsには組み込みのデータキャッシュがあり、データの取得結果を**サーバーリクエスト**と**デプロイメント**間で**保持**します。これは、Next.jsがネイティブの`fetch` APIを拡張し、サーバー上の各リクエストが独自の永続的なキャッシングセマンティクスを設定できるようにすることで可能です。 +Next.jsには、**サーバーリクエスト**および**デプロイ**間でデータフェッチの結果を**永続**するための組み込みData Cacheがあります。これは、Next.jsがネイティブの`fetch`APIを拡張して、サーバー上の各リクエストで独自の永続的なキャッシュセマンティクスを設定できるようにすることで実現可能です。 -> **Good to know**: ブラウザでは、`fetch`の`cache`オプションはリクエストがブラウザのHTTPキャッシュとどのように相互作用するかを示しますが、Next.jsでは、`cache`オプションはサーバー側のリクエストがサーバーのデータキャッシュとどのように相互作用するかを示します。 +> **Good to know**: ブラウザでは、`fetch`の`cache`オプションはリクエストがブラウザのHTTPキャッシュとどのように相互作用するかを示しますが、Next.jsでは、`cache`オプションはサーバー側リクエストがサーバーのData Cacheとどのように相互作用するかを示します。 -`fetch`の[`cache`](#fetch-optionscache)および[`next.revalidate`](#fetch-optionsnextrevalidate)オプションを使用して、キャッシング動作を設定できます。 +`fetch`の[`cache`](#fetch-optionscache)および[`next.revalidate`](#fetch-optionsnextrevalidate)オプションを使用して、キャッシュの動作を設定できます。 -**データキャッシュの仕組み** +**Data Cacheの仕組み** データキャッシュと対話するキャッシュおよび非キャッシュのfetchリクエストの図。キャッシュリクエストはデータキャッシュに格納され、メモ化されます。非キャッシュリクエストはデータソースから取得され、データキャッシュに格納されず、メモ化されます。 -- `'force-cache'`オプション付きの`fetch`リクエストがレンダリング中に初めて呼び出されたとき、Next.jsはデータキャッシュにキャッシュされた応答があるか確認します。 -- キャッシュされた応答が見つかった場合、それはすぐに返され、[メモ化されます](#request-memoization)。 -- キャッシュされた応答が見つからなかった場合、リクエストがデータソースに送られ、その結果がデータキャッシュに保存され、メモ化されます。 -- 非キャッシュデータ(例:`cache`オプションが定義されていないまたは`{ cache: 'no-store' }`を使用)は、結果が常にデータソースから取得され、メモ化されます。 -- データがキャッシュされているかどうかにかかわらず、同じデータに対する重複したリクエストを防ぐためにリクエストは常にメモ化され、Reactレンダリングパス中に行われます。 +- レンダリング中に`fetch`リクエストが`'force-cache'`オプションで初めて呼び出されると、Next.jsはData Cacheにキャッシュされたレスポンスがあるかどうかを確認します。 +- キャッシュされたレスポンスが見つかると、それはすぐに返され、[メモ化](#request-memoization)されます。 +- キャッシュされたレスポンスが見つからない場合、リクエストはデータソースに対して行われ、結果がData Cacheに保存され、メモ化されます。 +- キャッシュされないデータの場合(例:`cache`オプションが定義されていない場合、または `{ cache: 'no-store' }`を使用している場合)、結果は常にデータソースからフェッチされ、メモ化されます。 +- データがキャッシュされているかされていないかに関わらず、リクエストは常にメモ化され、Reactレンダーパス中に同じデータの重複リクエストを行わないようにします。 -> **データキャッシュとリクエストメモ化の違い** +> **Data CacheとRequest Memoizationの違い** > -> 両方のキャッシングメカニズムは、キャッシュされたデータを再利用することによってパフォーマンスを向上させますが、データキャッシュはリクエストとデプロイメントにまたがって永続的に維持されるのに対し、メモ化はリクエストのライフタイム内でのみ持続します。 +> 両方のキャッシュメカニズムがキャッシュされたデータを再利用することでパフォーマンスを向上させるのに役立ちますが、Data Cacheは受信リクエストとデプロイメントを通じて永続的であるのに対し、メモ化はリクエストの寿命のみ持続します。 ### 期間 {#duration} -データキャッシュは、再検証またはオプトアウトが行われない限り、リクエストやデプロイメント間で永続的に保持されます。 +Data Cacheは再検証またはオプトアウトしない限り、受信リクエストとデプロイメントを通じて永続的です。 ### 再検証 {#revalidating} キャッシュされたデータは次の2つの方法で再検証できます: -- **時間ベースの再検証**: 一定時間経過後の新しいリクエストでデータを再検証します。これは、データがあまり頻繁に変化せず、新鮮さがあまり重要でない場合に有用です。 -- **オンデマンドの再検証**: イベントに基づいてデータを再検証します(例:フォーム送信)。オンデマンドの再検証はタグベースまたはパスベースのアプローチを使用してデータのグループを一度に再検証できます。例えば、無頭CMSのコンテンツが更新されたときに最新のデータをすぐに表示したい場合に有効です。 +- **時間ベースの再検証**:一定時間が経過した後、リクエストが新たに行われたときにデータを再検証します。これは変更が少なく、最新であることが重要でないデータに役立ちます。 +- **オンデマンド再検証:** イベントに基づいてデータを再検証します(例:フォーム送信時)。オンデマンド再検証は、タグベースまたはパスベースのアプローチを使用して、データのグループを一括で再検証できます。これは、コンテンツの最新状態をできるだけ早く表示したい場合に役立ちます(例:ヘッドレスCMSのコンテンツが更新された場合)。 #### 時間ベースの再検証 {#time-based-revalidation} -特定の時間間隔でデータを再検証するには、`fetch`における`next.revalidate`オプションを使用して、リソースのキャッシュライフタイム(秒単位)を設定します。 +特定の間隔でデータを再検証するには、`fetch`の`next.revalidate`オプションを使用してリソースのキャッシュ期間(秒単位)を設定できます。 ```js -// 最大で毎時再生性を検証 +// 最大1時間ごとに再検証します fetch('https://...', { next: { revalidate: 3600 } }) ``` -または、[ルートセグメント設定オプション](#segment-config-options)を使用して、セグメント内のすべての`fetch`リクエストを設定したり、`fetch`を使用できない場合に設定できます。 +または、[Route Segment Configオプション](#segment-config-options)を使用して、セグメント内のすべての`fetch`リクエストを設定するか、`fetch`を使用できない場合にそれを使用できます。 **時間ベースの再検証の仕組み** 時間ベースの再検証の仕組みを示す図で、再検証期間後、最初のリクエストに対して古いデータが返され、次にデータが再検証されます。 -- `fetch`リクエストが最初に`revalidate`を指定して呼び出されたとき、外部データソースからデータが取得され、データキャッシュに保存されます。 -- 指定された時間枠内に呼び出されたリクエストは、キャッシュされたデータを返します。 -- 時間枠が経過した後、次のリクエストはまだキャッシュ(現在は古い)データを返します。 +- `revalidate`付きのfetchリクエストが初めて呼び出されると、データが外部データソースからフェッチされ、Data Cacheに保存されます。 +- 指定された時間枠内で呼び出されるリクエストはキャッシュされたデータを返します。 +- この時間枠が経過すると、次回のリクエストは依然としてキャッシュされた(古い)データを返します。 - Next.jsはバックグラウンドでデータの再検証をトリガーします。 - - データが正常に取得されると、Next.jsは新鮮なデータでデータキャッシュを更新します。 - - バックグラウンド再検証が失敗した場合、前のデータはそのまま残ります。 + - データが正常にフェッチされると、Next.jsは新鮮なデータでData Cacheを更新します。 + - バックグラウンド再検証が失敗した場合、以前のデータは変更されずに保持されます。 -これは[**stale-while-revalidate**](https://web.dev/stale-while-revalidate/)動作に似ています。 +これは[**stale-while-revalidate**](https://web.dev/stale-while-revalidate/)の動作に似ています。 #### オンデマンド再検証 {#on-demand-revalidation} -データはパスごとに([`revalidatePath`](#revalidatepath))またはキャッシュタグごとに([`revalidateTag`](#fetch-optionsnexttags-and-revalidatetag))オンデマンドで再検証できます。 +データは、パス([`revalidatePath`](#revalidatepath))またはキャッシュタグ([`revalidateTag`](#fetch-optionsnexttags-and-revalidatetag))でオンデマンドで再検証できます。 **オンデマンド再検証の仕組み** オンデマンド再検証の仕組みを示す図で、データキャッシュが再検証リクエスト後に新鮮なデータで更新される仕組みを示します。 -- `fetch`リクエストが初めて呼び出されたとき、データが外部データソースから取得され、データキャッシュに保存されます。 -- オンデマンド再検証がトリガーされると、適切なキャッシュエントリはキャッシュから削除されます。 - - これは、古いデータをキャッシュに保持する時間ベースの再検証とは異なり、データが取得されるまでキャッシュに残ります。 -- 次回のリクエストが行われたとき、再びキャッシュの`MISS`となり、データが外部データソースから取得され、データキャッシュに保存されます。 +- `fetch`リクエストが初めて呼び出されると、データが外部データソースからフェッチされ、Data Cacheに保存されます。 +- オンデマンド再検証がトリガーされた場合、適切なキャッシュエントリはキャッシュから削除されます。 + - これは、古いデータをフェッチするまでキャッシュに保持する時間ベースの再検証とは異なります。 +- 次にリクエストが行われたとき、再びキャッシュ`MISS`となり、データが外部データソースからフェッチされ、Data Cacheに保存されます。 ### オプトアウト {#opting-out} -`fetch`からの応答をキャッシュしたくない場合、以下のようにできます: +`fetch`からのレスポンスをキャッシュしたくない場合は、次のように設定できます: ```js let data = await fetch('https://api.vercel.app/blog', { cache: 'no-store' }) ``` -## フルルートキャッシュ {#full-route-cache} +## Full Route Cache {#full-route-cache} -> **関連する用語**: +> **関連用語**: > -> 自動静的最適化、静的サイト生成、または静的レンダリングという用語が、アプリケーションのルートをビルド時にレンダリングおよびキャッシュするプロセスを指すために互換的に使用されることがあります。 +> アプリケーションのルートをビルド時にレンダリングおよびキャッシュするプロセスを指して、**Automatic Static Optimization**、**Static Site Generation**、または**Static Rendering**という用語を使用することがあります。 -Next.jsはデフォルトでルートをビルドタイムにレンダリングし、キャッシュします。これは、個々のリクエストごとにサーバーでレンダリングする代わりにキャッシュされたルートを提供できる最適化であり、高速なページ読み込みを実現します。 +Next.jsはビルド時にルートを自動的にレンダリングし、キャッシュします。これにより、すべてのリクエストに対してサーバーでレンダリングする代わりに、キャッシュされたルートを提供することができ、高速なページロードを実現します。 -フルルートキャッシュがどのように機能するかを理解するために、Reactがレンダリングをどのように扱うか、およびNext.jsがその結果をどのようにキャッシュするかを見ると役立ちます: +Full Route Cacheの仕組みを理解するには、Reactがレンダリングをどのように処理し、Next.jsがその結果をどのようにキャッシュするかを見ることが役立ちます: -### 1. サーバーにおけるReactレンダリング {#1-react-rendering-on-the-server} +### 1. サーバーでのReactレンダリング {#1-react-rendering-on-the-server} -サーバーでは、Next.jsはReactのAPIを使用してレンダリングを調整します。レンダリング作業は、個々のルートセグメントおよびSuspenseバウンダリーごとに分割されます。 +サーバー上で、Next.jsはReactのAPIを使用してレンダリングを調整します。レンダリング作業は、個々のルートセグメントやSuspense境界によって分割されます。 各チャンクは2つのステップでレンダリングされます: -1. ReactはServer Componentsをストリーミングに最適化された特別なデータフォーマットにレンダリングします。これは**React Server Component Payload**と呼ばれます。 -2. Next.jsはReact Server Component PayloadとクライアントのJavaScript命令を使用して、サーバー上で**HTML**をレンダリングします。 +1. Reactはサーバーコンポーネントをストリーミングに最適化された特別なデータ形式である**Reactサーバーコンポーネントペイロード**にレンダリングします。 +2. Next.jsはReactサーバーコンポーネントペイロードとクライアントコンポーネントJavaScript命令を使用して、**HTML**をサーバーでレンダリングします。 -これにより、すべてがレンダリングされるのを待たずに作業をキャッシュしたり、応答を送信することができます。代わりに、作業が完了するたびに応答をストリーミングできるようになります。 +これにより、すべてをレンダリングし終えるまで作業をキャッシュしたり、レスポンスを送信したりする必要がなくなります。代わりに、作業が完了すると、レスポンスをストリーミングできます。 -> **React Server Component Payloadとは何か?** +> **Reactサーバーコンポーネントペイロードとは?** > -> React Server Component Payloadは、レンダリングされたReact Server Components treeのコンパクトなバイナリ表現です。クライアント上のReactにより、ブラウザのDOMを更新するために使用されます。React Server Component Payloadには以下が含まれます: +> Reactサーバーコンポーネントペイロードは、レンダリングされたReactサーバーコンポーネントツリーのコンパクトなバイナリ表現です。クライアントのReactによってブラウザのDOMを更新するために使用されます。このペイロードには次が含まれます: > -> - Server Componentsのレンダリング結果 -> - クライアント ComponentsのJavaScriptファイルのプレースホルダーとその参照 -> - Server Componentsからクライアント Componentsに渡されたprops +> - サーバーコンポーネントのレンダリング結果 +> - クライアントコンポーネントのレンダリング場所とそのJavaScriptファイルへの参照 +> - サーバーコンポーネントからクライアントコンポーネントに渡されるany props > -> 詳細は、[Server Components](/docs/app/building-your-application/rendering/server-components)のドキュメントをご覧ください。 +> 詳しくは、[サーバーコンポーネント](/docs/app/building-your-application/rendering/server-components)ドキュメントをご覧ください。 -### 2. サーバーでのNext.jsキャッシング(フルルートキャッシュ) {#2-next-js-caching-on-the-server-full-route-cache} +### 2. サーバーでのNext.jsキャッシュ(Full Route Cache) {#2-next-js-caching-on-the-server-full-route-cache} Next.jsのデフォルトのフルルートキャッシュの動作を示しており、React Server Component PayloadとHTMLがサーバーでキャッシュされる様子を示しています。 -Next.jsのデフォルトの動作は、ルートのレンダリング結果(React Server Component PayloadとHTML)をサーバーでキャッシュすることです。これはビルドタイムや再検証時に静的にレンダリングされたルートに適用されます。 +Next.jsのデフォルト動作は、サーバーでルートのレンダリング結果(ReactサーバーコンポーネントペイロードとHTML)をキャッシュすることです。これは、ビルド時または再検証時に静的にレンダリングされたルートに適用されます。 -### 3. クライアントでのReact実行と同期 {#3-react-hydration-and-reconciliation-on-the-client} +### 3. クライアントでのReactのハイドレーションと調整 {#3-react-hydration-and-reconciliation-on-the-client} -リクエスト時にクライアントでは: +リクエスト時、クライアント側では: -1. HTMLは、クライアントとServer Componentsの非対話型の初期プレビューをすぐに表示するために使用されます。 -2. React Server Components Payloadは、クライアントとレンダリングされたServer Component treesを統合して、DOMを更新するために使用されます。 -3. JavaScript命令は、クライアント Componentsを[実行](https://react.dev/reference/react-dom/client/hydrateRoot)してアプリケーションを対話型にします。 +1. HTMLを使用して、クライアントおよびサーバーコンポーネントのインタラクティブでない初期プレビューを即座に表示します。 +2. Reactサーバーコンポーネントペイロードを使用して、クライアントとレンダリングされたサーバーコンポーネントツリーを調整し、DOMを更新します。 +3. JavaScript命令を使用して[クライアントコンポーネントをハイドレート](https://react.dev/reference/react-dom/client/hydrateRoot)し、アプリケーションをインタラクティブにします。 -### 4. クライアントでのNext.jsキャッシング(ルーターキャッシュ) {#4-next-js-caching-on-the-client-router-cache} +### 4. クライアントでのNext.jsキャッシュ(Router Cache) {#4-next-js-caching-on-the-client-router-cache} -React Server Component Payloadは、クライアント側の[Router Cache](#client-side-router-cache)に格納されます。これは、個々のルートセグメントごとに分割されたメモリキャッシュです。このRouter Cacheは、以前に訪問したルートを保存し、将来的に訪問する可能性のあるルートを事前に取得するために使用されます。 +Reactサーバーコンポーネントペイロードは、クライアント側の[Router Cache](#client-side-router-cache)に保存されます。これは、個々のルートセグメントによって分割されたメモリキャッシュです。このRouter Cacheは、以前訪れたルートを保存し、将来のルートを事前フェッチすることで、ナビゲーション経験を向上させるために使用されます。 ### 5. 後続のナビゲーション {#5-subsequent-navigations} -後続のナビゲーションや事前取得中、Next.jsはRouter CacheにReact Server Components Payloadが保存されているかどうかを確認します。保存されている場合は、新しいサーバーリクエストを送信することをスキップします。 +後続のナビゲーションや事前フェッチ中、Next.jsはRouter CacheにReactサーバーコンポーネントペイロードが保存されているかどうかを確認します。そうであれば、新たにサーバーにリクエストを送信することをスキップします。 -ルートセグメントがキャッシュにない場合、Next.jsはサーバーからReact Server Components Payloadを取得し、クライアントのRouter Cacheに追加します。 +ルートセグメントがキャッシュにない場合、Next.jsはサーバーからReactサーバーコンポーネントペイロードをフェッチし、クライアントのRouter Cacheに置きます。 -### 静的と動的レンダリング {#static-and-dynamic-rendering} +### 静的および動的レンダリング {#static-and-dynamic-rendering} -ルートがビルドタイムにキャッシュされるかどうかは、そのルートが静的または動的にレンダリングされるかどうかに依存します。静的ルートはデフォルトでキャッシュされ、動的ルートはリクエスト時にレンダリングされ、キャッシュされません。 +ルートがビルド時にキャッシュされるかどうかは、そのルートが静的レンダリングか動的レンダリングかによります。静的ルートはデフォルトでキャッシュされますが、動的ルートはリクエスト時にレンダリングされ、キャッシュされません。 -以下の図は、静的および動的にレンダリングされたルートの違いを示しており、キャッシュデータと非キャッシュデータが示されています: +この図は、静的および動的にレンダリングされたルートと、キャッシュされたデータとキャッシュされていないデータとの違いを示しています: 静的および動的レンダリングがフルルートキャッシュに与える影響を示す図。静的ルートはビルドタイムまたはデータ再検証後にキャッシュされ、動的ルートは決してキャッシュされない。 **Good to know:** このキャッシュはNext.jsとServer Componentsに特有であり、ブラウザの[bfcache](https://web.dev/bfcache/)とは異なりますが、似たような結果をもたらします。 +> **Good to know:** このキャッシュは特にNext.jsおよびサーバーコンポーネントに適用され、ブラウザーの[bfcache](https://web.dev/bfcache/)とは異なりますが、結果は似ています。 ### 期間 {#duration} -キャッシュはブラウザの一時メモリに格納されます。2つの要因がルーターキャッシュの存続期間を決定します: +キャッシュはブラウザーの一時メモリに保存されます。2つの要因がrouter cacheの持続期間を決定します: -- **セッション**: ナビゲーション中にキャッシュは持続します。ただし、ページの再読み込みでクリアされます。 -- **自動無効化期間**: レイアウトと読み込み状態のキャッシュは、指定された時間後に自動的に無効化されます。期間は、リソースがどのように[事前取得された](/docs/app/api-reference/components/link#prefetch)か、そしてリソースが[静的に生成された](/docs/app/building-your-application/rendering/server-components#static-rendering-default)かに依存します: - - **デフォルトの事前取得**(`prefetch={null}`または指定なし): 動的ページにはキャッシュされません、静的ページには5分間。 - - **完全な事前取得**(`prefetch={true}`または`router.prefetch`): 静的および動的ページの両方に対して5分間。 +- **セッション**: キャッシュはナビゲーション中に持続しますが、ページをリフレッシュするとクリアされます。 +- **自動無効化期間**: レイアウトとロード状態のキャッシュは、特定の時間が経過すると自動的に無効化されます。この期間は、リソースが[プリフェッチされた](/docs/app/api-reference/components/link#prefetch)方法と、リソースが[静的に生成された](/docs/app/building-your-application/rendering/server-components#static-rendering-default)かどうかによって異なります: + - **デフォルトのプリフェッチング**(`prefetch={null}`または指定されていない):動的ページの場合はキャッシュされず、静的ページの場合は5分。 + - **フルプリフェッチング**(`prefetch={true}`または`router.prefetch`):静的ページと動的ページの両方の場合は5分。 -ページの再読み込みは**すべて**のキャッシュセグメントをクリアしますが、自動無効化期間は、事前取得された時間からの個々のセグメントのみに影響します。 +ページをリフレッシュすると、**すべて**のキャッシュされたセグメントがクリアされますが、自動無効化期間はプリフェッチされた時点から個々のセグメントにだけ影響します。 -> **Good to know**: 実験オプション[`staleTimes`](/docs/app/api-reference/config/next-config-js/staleTimes)を使用して上記の自動無効化時間を調整することができます。 +> **Good to know**: 実験的な[`staleTimes`](/docs/app/api-reference/config/next-config-js/staleTimes)設定オプションを使用して、上記の自動無効化時間を調整できます。 ### 無効化 {#invalidation} -ルーターキャッシュを無効化する方法は次の2つです: +Router Cacheを無効化する方法は2つあります: -- **Server Action** の中で: - - パスでのオンデマンド再検証は([`revalidatePath`](/docs/app/api-reference/functions/revalidatePath))タグでのキャッシュ再検証は([`revalidateTag`](/docs/app/api-reference/functions/revalidateTag)) - - [`cookies.set`](/docs/app/api-reference/functions/cookies#setting-a-cookie)または[`cookies.delete`](/docs/app/api-reference/functions/cookies#deleting-cookies)を使用してルーターキャッシュを無効にし、クッキーを使用するルートが古くなるのを防ぐ(例:認証)。 -- [`router.refresh`](/docs/app/api-reference/functions/use-router)を呼び出すことでルーターキャッシュを無効にし、現在のルートに対するサーバーへの新しいリクエストを行う。 +- **Server Action**で: + - ([`revalidatePath`](/docs/app/api-reference/functions/revalidatePath))または([`revalidateTag`](/docs/app/api-reference/functions/revalidateTag))を使用してパスによるオンデマンド再検証。 + - [`cookies.set`](/docs/app/api-reference/functions/cookies#setting-a-cookie)または[`cookies.delete`](/docs/app/api-reference/functions/cookies#deleting-cookies)を使用することで、クッキーを使用するルートが古くならないようにRouter Cacheを無効にします(例:認証)。 +- [`router.refresh`](/docs/app/api-reference/functions/use-router)を呼び出すことで、Router Cacheを無効化し、現在のルートに対して新しいリクエストをサーバーに送信します。 ### オプトアウト {#opting-out} -Next.js 15以降、ページセグメントはデフォルトでオプトアウトされています。 +Next.js 15以降では、ページセグメントはデフォルトでオプトアウトされています。 -> **Good to know:** ``コンポーネントの`prefetch`プロップを`false`に設定することで、[事前取得](/docs/app/building-your-application/routing/linking-and-navigating#2-prefetching)をオプトアウトすることもできます。 +> **Good to know:** ``コンポーネントの`prefetch` propを`false`に設定することで、[プリフェッチング](/docs/app/building-your-application/routing/linking-and-navigating#2-prefetching)をオプトアウトすることもできます。 ## キャッシュの相互作用 {#cache-interactions} -さまざまなキャッシングメカニズムを設定する際、相互作用を理解することが重要です: +異なるキャッシュメカニズムを設定するとき、それらがどのように相互作用するかを理解することが重要です: -### データキャッシュとフルルートキャッシュ {#data-cache-and-full-route-cache} +### Data CacheとFull Route Cache {#data-cache-and-full-route-cache} -- データキャッシュを再検証またはオプトアウトすることは、フルルートキャッシュを無効化します。なぜなら、レンダー出力はデータに依存しているからです。 -- フルルートキャッシュを無効化またはオプトアウトしても、データキャッシュには影響しません。キャッシュされたデータとキャッシュされていないデータの両方を持つルートを動的にレンダリングできます。たとえば、ほとんどのページがキャッシュされたデータを使用する場合でも、いくつかのコンポーネントがリクエスト時に取得する必要のあるデータに依存していることに有用です。すべてのデータを再取得する際のパフォーマンスへの影響を心配せずに動的レンダリングできます。 +- Data Cacheを再検証またはオプトアウトすると、Full Route Cacheは**無効化**されます。なぜなら、レンダリングの結果はデータに依存するからです。 +- Full Route Cacheを無効化またはオプトアウトしても、Data Cacheは影響を受けません。キャッシュされたデータとキャッシュされていないデータの両方を持つルートを動的にレンダリングすることができます。これは、ページのほとんどがキャッシュされたデータを使用しているが、いくつかのコンポーネントがリクエスト時にフェッチする必要があるデータに依存している場合に便利です。すべてのデータを再フェッチするパフォーマンスへの影響を心配することなく、動的にレンダリング可能です。 -### データキャッシュとクライアントサイドのルーターキャッシュ {#data-cache-and-client-side-router-cache} +### Data CacheとクライアントサイドRouter Cache {#data-cache-and-client-side-router-cache} -- データキャッシュとルーターキャッシュを即座に無効化するには[Server Action](/docs/app/building-your-application/data-fetching/server-actions-and-mutations)で[`revalidatePath`](#revalidatepath)または[`revalidateTag`](#fetch-optionsnexttags-and-revalidatetag)を使用できます。 -- [Route Handler](/docs/app/building-your-application/routing/route-handlers)でデータキャッシュを再検証しても、Router Cacheは直ちには無効化されません。これらのRoute Handlerは特定のルートに結び付けられていないため、Router Cacheはハードリフレッシュまたは自動無効化期間が経過するまで以前のペイロードを提供し続けます。 +- Data CacheとRouter Cacheを即時に無効化するには、[Server Action](/docs/app/building-your-application/data-fetching/server-actions-and-mutations)で[`revalidatePath`](#revalidatepath)または[`revalidateTag`](#fetch-optionsnexttags-and-revalidatetag)を使用できます。 +- [Route Handler](/docs/app/building-your-application/routing/route-handlers)でData Cacheを再検証しても、Router Cacheは即時に無効化されません。なぜなら、Route Handlerは特定のルートに結びついていないからです。つまり、Router Cacheはハードリフレッシュが行われるまで、または自動無効化期間が経過するまで、前のペイロードを配信し続けます。 ## API {#apis} -次の表は、さまざまなNext.js APIがキャッシングにどのような影響を与えるかの概要を示しています: +以下の表は、さまざまなNext.js APIがキャッシュにどのように影響するかの概要を示しています: -| API | Router Cache | フルルートキャッシュ | Data Cache | React Cache | +| API | Router Cache | Full Route Cache | Data Cache | React Cache | | ----------------------------------------------------------------------- | -------------------------- | --------------------- | --------------------- | ----------- | | [``](#link) | Cache | | | | | [`router.prefetch`](#routerprefetch) | Cache | | | | @@ -400,139 +400,138 @@ Next.js 15以降、ページセグメントはデフォルトでオプトアウ ### `` {#link} -デフォルトでは、``コンポーネントはフルルートキャッシュからルートを自動的に事前取得し、Router CacheにReact Server Component Payloadを追加します。 +デフォルトでは、``コンポーネントはFull Route Cacheからルートを自動的にプリフェッチし、Router CacheにReactサーバーコンポーネントペイロードを追加します。 -事前取得を無効にするには、`prefetch`プロパティを`false`に設定します。ただし、これはキャッシュを永続的にスキップすることはなく、ユーザーがルートを訪問したときにルートセグメントはクライアント側でキャッシュされます。 +プリフェッチを無効にするには、`prefetch` propを`false`に設定できます。しかし、これによりキャッシュが恒久的にスキップされることはなく、ユーザーがルートを訪問したときにルートセグメントはクライアント側でまだキャッシュされます。 -[``コンポーネント](/docs/app/api-reference/components/link)の詳細を学ぶ。 +[``コンポーネント](/docs/app/api-reference/components/link)について詳しく学ぶ。 ### `router.prefetch` {#router-prefetch} -`useRouter`フックの`prefetch`プロパティを使用して、ルートを手動で事前取得できます。これにより、Router CacheにReact Server Component Payloadを追加します。 +`router.prefetch`オプションを使用して手動でルートをプリフェッチできます。これにより、ReactサーバーコンポーネントペイロードがRouter Cacheに追加されます。 -[`useRouter`フック](/docs/app/api-reference/functions/use-router)のAPIリファレンスを参照してください。 +[`useRouter` hook](/docs/app/api-reference/functions/use-router)のAPIリファレンスをご覧ください。 ### `router.refresh` {#router-refresh} -`useRouter`フックの`refresh`プロパティを使用して、ルートを手動で更新できます。これによりRouter Cacheが完全にクリアされ、現在のルートに対するサーバーへの新しいリクエストが行われます。`refresh`はデータキャッシュまたはフルルートキャッシュには影響を与えません。 +`refresh`オプションを使用することで、ルートを手動でリフレッシュできます。これにより、Router Cacheが完全にクリアされ、現在のルートに対して新しいリクエストがサーバーに送信されます。`refresh`はDataまたはFull Route Cacheには影響しません。 -描画結果はクライアント側で統合され、React状態やブラウザ状態が保持されます。 +レンダリングされた結果は、Reactの状態とブラウザーの状態を保持しながらクライアント側で調整されます。 -[`useRouter`フック](/docs/app/api-reference/functions/use-router)のAPIリファレンスを参照してください。 +[`useRouter` hook](/docs/app/api-reference/functions/use-router)のAPIリファレンスをご覧ください。 ### `fetch` {#fetch} -`fetch`から返されたデータは、自動的にデータキャッシュにキャッシュされます。 +`fetch`から返されるデータは、Data Cacheに自動的にキャッシュされません。 -`fetch`からの応答をキャッシュしたくない場合、以下のようにできます: +`fetch`のデフォルトのキャッシュ動作(例:`cache`オプションが指定されていない場合)は、`cache`オプションを`no-store`に設定した場合と同等です: ```js let data = await fetch('https://api.vercel.app/blog', { cache: 'no-store' }) ``` -[`fetch` APIリファレンス](/docs/app/api-reference/functions/fetch)でその他のオプションを確認してください。 +[`fetch` APIリファレンス](/docs/app/api-reference/functions/fetch)で他のオプションを確認してください。 ### `fetch options.cache` {#fetch-options-cache} -個々の`fetch`をキャッシュにオプトインする場合、`cache`オプションを`force-cache`に設定します: +個々の`fetch`をキャッシュにオプトインするには、`cache`オプションを`force-cache`に設定します: ```jsx // キャッシュにオプトイン fetch(`https://...`, { cache: 'force-cache' }) ``` -[`fetch` APIリファレンス](/docs/app/api-reference/functions/fetch)でその他のオプションを確認してください。 +[`fetch` APIリファレンス](/docs/app/api-reference/functions/fetch)で他のオプションを確認してください。 ### `fetch options.next.revalidate` {#fetch-options-next-revalidate} -`fetch`の`next.revalidate`オプションを使用して、個々の`fetch`リクエストの再検証期間(秒単位)を設定することができます。これによりデータキャッシュが再検証され、結果としてフルルートキャッシュも再検証されます。新鮮なデータが取得され、コンポーネントがサーバー上で再レンダリングされます。 +`fetch`の`next.revalidate`オプションを使用して、個々の`fetch`リクエストの再検証期間(秒単位)を設定できます。これによりData Cacheが再検証され、結果としてFull Route Cacheも再検証されます。新鮮なデータがフェッチされ、コンポーネントがサーバーで再レンダリングされます。 ```jsx -// 最大1時間後に再検証 +// 最大1時間ごとに再検証 fetch(`https://...`, { next: { revalidate: 3600 } }) ``` -[`fetch` APIリファレンス](/docs/app/api-reference/functions/fetch)でその他のオプションを確認してください。 +[`fetch` APIリファレンス](/docs/app/api-reference/functions/fetch)で他のオプションを確認してください。 -### `fetch options.next.tags` and `revalidateTag` {#fetch-options-next-tags-and-revalidatetag} +### `fetch options.next.tags`および`revalidateTag` {#fetch-options-next-tags-and-revalidatetag} -Next.jsには、細かなデータキャッシングと再検証のためのキャッシュタグシステムがあります。 +Next.jsには、細かいデータキャッシングと再検証のためのキャッシュタグシステムがあります。 -1. `fetch`や[`unstable_cache`](/docs/app/api-reference/functions/unstable_cache)を使用するときに、キャッシュエントリを1つ以上のタグでタグ付けするオプションがあります。 -2. その後、タグに関連付けられたキャッシュエントリを削除するために`revalidateTag`を呼び出すことができます。 +1. `fetch`または[`unstable_cache`](/docs/app/api-reference/functions/unstable_cache)を使用する場合、1つ以上のタグをキャッシュエントリに付けるオプションがあります。 +2. 次に、`revalidateTag`を呼び出して、そのタグに関連付けられたキャッシュエントリをパージできます。 -たとえば、データを取得する際にタグを設定できます: +たとえば、データをフェッチするときにタグを設定できます: ```jsx -// データをタグでキャッシュ +// キャッシュデータにタグを付ける fetch(`https://...`, { next: { tags: ['a', 'b', 'c'] } }) ``` -次に、特定のタグを持つキャッシュエントリを削除して`revalidateTag`を呼び出します: +次に、特定のタグでキャッシュエントリをパージするために`revalidateTag`を呼び出します: ```jsx // 特定のタグを持つエントリを再検証 revalidateTag('a') ``` -使用目的によって、`revalidateTag`を次の場所で使用できます: +どちらのケースも、あなたが達成しようとしていることに応じて、`revalidateTag`を使用できる場所が2つあります: -1. [Route Handlers](/docs/app/building-your-application/routing/route-handlers) - サードパーティーイベント(例:Webhook)の応答としてデータを再検証する。 - -2. [Server Actions](/docs/app/building-your-application/data-fetching/server-actions-and-mutations) - ユーザーアクション(例:フォーム送信)後にデータを再検証する。 この場合、関連するルートのRouter Cacheは無効化されます。 +1. [Route Handlers](/docs/app/building-your-application/routing/route-handlers) - サードパーティイベント(例:Webhook)の応答でデータを再検証します。Router Cacheはすぐには無効化されません。 +2. [Server Actions](/docs/app/building-your-application/data-fetching/server-actions-and-mutations) - ユーザーアクション(例:フォーム送信)後にデータを再検証します。関連するルートのRouter Cacheは無効化されます。 ### `revalidatePath` {#revalidatepath} -`revalidatePath`を使って、特定のパス以下のルートセグメントを再レンダリングしつつデータを手動で再検証することが可能です。このメソッドを呼び出すことでデータキャッシュが再検証され、その結果フルルートキャッシュも無効化されます。 +`revalidatePath`を使用すると、データを手動で再検証し、特定のパス以下のルートセグメントを単一の操作で再レンダリングできます。`revalidatePath`メソッドを呼び出すとData Cacheが再検証され、この結果としてFull Route Cacheが無効化されます。 ```jsx revalidatePath('/') ``` -使用目的によって、`revalidatePath`を次の場所で使用できます: +どちらのケースも、あなたが達成しようとしていることに応じて、`revalidatePath`を使用できる場所が2つあります: -1. [Route Handlers](/docs/app/building-your-application/routing/route-handlers) - サードパーティーイベント(例:Webhook)の応答としてデータを再検証する。 -2. [Server Actions](/docs/app/building-your-application/data-fetching/server-actions-and-mutations) - ユーザーインタラクション(例:フォーム送信、ボタンのクリック)後にデータを再検証する。 +1. [Route Handlers](/docs/app/building-your-application/routing/route-handlers) - サードパーティイベント(例:Webhook)の応答でデータを再検証します。 +2. [Server Actions](/docs/app/building-your-application/data-fetching/server-actions-and-mutations) - ユーザーインタラクション(例:フォーム送信、ボタンクリック)後にデータを再検証します。 [`revalidatePath` APIリファレンス](/docs/app/api-reference/functions/revalidatePath)で詳細を確認してください。 -> **`revalidatePath`** と **`router.refresh`**: +> **`revalidatePath`** vs. **`router.refresh`**: > -> `router.refresh`を呼び出すと、Router Cacheがクリアされ、サーバー上でルートセグメントが再レンダリングされますが、データキャッシュやフルルートキャッシュは無効化されません。 +> `router.refresh`を呼び出すと、Router Cacheがクリアされ、Data CacheまたはFull Route Cacheを無効化せずにサーバーでルートセグメントが再レンダリングされます。 > -> `revalidatePath`はデータキャッシュとフルルートキャッシュをクリアしますが、`router.refresh()`はデータキャッシュとフルルートキャッシュを変更しないという違いがあります。 +> 違いは、`revalidatePath`がData CacheとFull Route Cacheをパージするのに対し、`router.refresh()`はData CacheとFull Route Cacheに影響しない点です。なぜなら、これはクライアントサイドAPIだからです。 -### 動的API {#dynamic-apis} +### Dynamic API {#dynamic-apis} -`cookies`や`headers`のような動的API、およびPages内の`searchParams`プロップは実行時のインカミングリクエスト情報に依存します。これらを使用すると、ルートがフルルートキャッシュからオプトアウトし、つまり、ルートが動的にレンダリングされることになります。 +`cookies`や`headers`などのDynamic API、Pagesでの`searchParams` propは、ランタイムの受信リクエスト情報に依存します。それらを使用することで、ルートはFull Route Cacheからオプトアウトされ、動的にレンダリングされます。 #### `cookies` {#cookies} -Server Action内で`cookies.set`または`cookies.delete`を使用すると、それを使用するルートが古くならないように、Router Cacheを無効にします(例:認証の変更を反映するため)。 +`cookies.set`や`cookies.delete`をServer Action内で使用すると、Router Cacheが無効化され、クッキーを使用するルートが古くならないようにします(例:認証の変更を反映するため)。 -[`cookies`](/docs/app/api-reference/functions/cookies) APIリファレンスを参照してください。 +[`cookies`](/docs/app/api-reference/functions/cookies)APIリファレンスをご覧ください。 -### セグメント設定オプション {#segment-config-options} +### Route Segment Configオプション {#segment-config-options} -ルートセグメント設定オプションは、`fetch` APIを使用できない場合(例:データベースクライアントやサードパーティライブラリ)またはデフォルトを上書きする場合に、ルートセグメントの設定をオーバーライドするために使用できます。 +Route Segment Configオプションは、ルートセグメントのデフォルトを上書きするか、`fetch` APIが使用できない場合(例:データベースクライアントまたはサードパーティライブラリ)に使用できます。 -次のルートセグメント設定オプションはフルルートキャッシュをオプトアウトします: +次のRoute Segment Configオプションは、Full Route Cacheのオプトアウトに使用できます: - `const dynamic = 'force-dynamic'` -この設定オプションは、すべてのフェッチをデータキャッシュからオプトアウトします(すなわち`no-store`): +この設定オプションを使用すると、すべてのfetchがData Cacheからオプトアウトされます(つまり、`no-store`): - `const fetchCache = 'default-no-store'` -[`fetchCache`](/docs/app/api-reference/file-conventions/route-segment-config#fetchcache)でより高度なオプションを確認してください。 +[`fetchCache`](/docs/app/api-reference/file-conventions/route-segment-config#fetchcache)で高度なオプションを確認してください。 -[ルートセグメント設定](/docs/app/api-reference/file-conventions/route-segment-config)のドキュメントで詳細なオプションを確認してください。 +[Route Segment Config](/docs/app/api-reference/file-conventions/route-segment-config)のドキュメントで他のオプションを確認してください。 ### `generateStaticParams` {#generatestaticparams} -[動的セグメント](/docs/app/building-your-application/routing/dynamic-routes)(例:`app/blog/[slug]/page.js`)について、`generateStaticParams`によって提供されるパスはビルドタイムにフルルートキャッシュにキャッシュされます。リクエスト時にNext.jsはビルドタイムに知られていなかったパスを初めて訪問した際にもキャッシュします。 +[動的セグメント](/docs/app/building-your-application/routing/dynamic-routes)(例:`app/blog/[slug]/page.js`)の場合、`generateStaticParams`が提供するパスはビルド時にFull Route Cacheにキャッシュされます。リクエスト時、Next.jsは知られていないパスもキャッシュし、最初にそれらが訪問されたときにキャッシュされます。 -ビルドタイムにすべてのパスを静的にレンダリングするには、`generateStaticParams`にパスの完全なリストを提供します: +すべてのパスをビルド時に静的にレンダリングするには、`generateStaticParams`にパスの完全なリストを提供します: ```jsx title="app/blog/[slug]/page.js" export async function generateStaticParams() { @@ -544,20 +543,20 @@ export async function generateStaticParams() { } ``` -ビルドタイムに一部のパスを静的にレンダリングし、残りは実行時に初めて訪問したときにレンダリングするには、部分的なパスのリストを返します: +ビルド時に一部のパスだけを静的にレンダリングし、残りをランタイムで最初に訪問されたときにレンダリングするには、部分的なリストを返します: ```jsx title="app/blog/[slug]/page.js" export async function generateStaticParams() { const posts = await fetch('https://.../posts').then((res) => res.json()) - // ビルドタイムに最初の10投稿をレンダリングする + // 最初の10件の投稿をビルド時にレンダリング return posts.slice(0, 10).map((post) => ({ slug: post.slug, })) } ``` -訪問時に初めてすべてのパスを静的にレンダリングするには、空の配列を返します(ビルドタイムにはパスはレンダリングされませnん)または[`export const dynamic = 'force-static'`](/docs/app/api-reference/file-conventions/route-segment-config#dynamic)を利用します: +訪問された最初の時点でパスをすべて静的にレンダリングするには、空の配列を返すか(ビルド時にはパスがレンダリングされません)、[`export const dynamic = 'force-static'`](/docs/app/api-reference/file-conventions/route-segment-config#dynamic)を利用します: ```jsx title="app/blog/[slug]/page.js" export async function generateStaticParams() { @@ -565,19 +564,19 @@ export async function generateStaticParams() { } ``` -> **Good to know:** `generateStaticParams`から配列を返す必要があります。たとえそれが空でもそうです。さもなければ、ルートは動的にレンダリングされます。 +> **Good to know:** `generateStaticParams`からは必ず配列を返す必要があります。たとえそれが空であっても。そうしないと、ルートは動的にレンダリングされます。 ```jsx title="app/changelog/[slug]/page.js" export const dynamic = 'force-static' ``` -リクエスト時のキャッシングを無効にするには、ルートセグメントに`export const dynamicParams = false`オプションを追加します。この設定オプションが使用された場合、`generateStaticParams`によって提供されたパスのみが提供され、その他のルートは404になったり(一致した場合には[catch-all routes](/docs/app/building-your-application/routing/dynamic-routes#catch-all-segments))になります。 +リクエスト時にキャッシュを無効にするには、ルートセグメント内に`export const dynamicParams = false`オプションを追加します。この設定オプションが使用されている場合、`generateStaticParams`で提供されたパスのみが提供され、他のルートは404になるか([catch-allルート](/docs/app/building-your-application/routing/dynamic-routes#catch-all-segments)のケース)一致します。 ### React `cache`関数 {#react-cache-function} -Reactの`cache`関数を使用すると、関数の戻り値をメモ化でき、同じ関数を複数回呼び出しながらも、一度だけ実行することができます。 +Reactの`cache`関数を使用すると、関数の戻り値をメモ化することができ、同じ関数を複数回呼び出しながら、1回だけ実行することができます。 -`fetch`リクエストは自動的にメモ化されるため、React `cache`でラップする必要はありませんが、`fetch` APIが適さない場合にデータリクエストを手動でメモ化するために`cache`を使用することができます。例えば、一部のデータベースクライアント、CMSクライアント、またはGraphQLクライアントなどの場合。 +`fetch`リクエストは自動的にメモ化されるため、Reactの`cache`でラップする必要はありませんが、`fetch` APIが適していないユースケースのためにデータリクエストを手動でメモ化するために`cache`を使用できます。たとえば、一部のデータベースクライアント、CMSクライアント、またはGraphQLクライアントです。 diff --git a/docs/01-app/02-building-your-application/05-styling/01-css.mdx b/docs/01-app/02-building-your-application/05-styling/01-css.mdx index b4bebda..1e2a330 100644 --- a/docs/01-app/02-building-your-application/05-styling/01-css.mdx +++ b/docs/01-app/02-building-your-application/05-styling/01-css.mdx @@ -1,38 +1,40 @@ --- title: 'CSS' nav_title: 'CSS' -description: 'CSS Modules、グローバルスタイル、外部スタイルシートでNext.jsアプリケーションをスタイリングする。' +description: 'Next.js アプリケーションを CSS モジュール、グローバルスタイル、外部スタイルシートでスタイリングしましょう。' --- -{/* このドキュメントの内容はapp routerとpages routerで共有されています。Pages Routerに特化したコンテンツを追加するためには、`Content`コンポーネントを使用してください。共有コンテンツはコンポーネントでラップしないでください。 */} +{/_ このドキュメントの内容は app router と pages router の両方で共有されています。 +`Content` コンポーネントを使用して、Pages Router に特有のコンテンツを追加できます。 +共有コンテンツはコンポーネントでラップしないでください。 _/}
              -- [基本的なCSSの例](https://github.com/vercel/next.js/tree/canary/examples/basic-css) +- [基本的な CSS の例](https://github.com/vercel/next.js/tree/canary/examples/basic-css)
              -Next.jsはCSSを処理するための複数の方法をサポートしています: +Next.js は CSS の処理を複数の方法でサポートしています: -- [CSS Modules](#css-modules) +- [CSS モジュール](#css-modules) - [グローバルスタイル](#global-styles) - [外部スタイルシート](#external-stylesheets) -## CSS Modules {#css-modules} +## CSS モジュール {#css-modules} -Next.jsには、`.module.css`拡張子を使用したCSS Modulesのサポートが組み込まれています。 +Next.js は `.module.css` 拡張子を使用して CSS モジュールを組み込みサポートしています。 -CSS Modulesは自動的に一意のクラス名を作成することで、CSSをローカルスコープにします。これにより、異なるファイルで同じクラス名を使用しても、衝突を心配する必要がありません。この動作により、CSS ModulesはコンポーネントレベルのCSSを含めるのに最適な方法となっています。 +CSS モジュールは自動的に一意のクラス名を作成することで CSS をローカルスコープにします。これにより、異なるファイルで同じクラス名を使用しても衝突を心配することなく使えるようになります。この動作により、CSS モジュールはコンポーネントレベルの CSS を含むための理想的な方法となります。 ### 例 {#example} -CSS Modulesは、`app`ディレクトリ内の任意のファイルにインポートできます: +CSS モジュールは、`app` ディレクトリ内の任意のファイルにインポートできます: @@ -73,13 +75,13 @@ export default function DashboardLayout({ children }) { -例えば、`components/`フォルダに再利用可能な`Button`コンポーネントを考えてみましょう: +例えば、`components/` フォルダ内の再利用可能な `Button` コンポーネントを考えてみましょう: -まず、次の内容で`components/Button.module.css`を作成します: +まず、以下の内容で `components/Button.module.css` を作成します: ```css title="Button.module.css" /* -.error {}が他の`.css`や`.module.css`ファイルと衝突する心配はありません! +.error {} が他の `.css` や `.module.css` ファイルと衝突することを心配する必要はありません! */ .error { color: white; @@ -87,7 +89,7 @@ export default function DashboardLayout({ children }) { } ``` -次に、上記のCSSファイルをインポートして使用する`components/Button.js`を作成します: +その後、上記の CSS ファイルをインポートして使用する `components/Button.js` を作成します: ```jsx title="components/Button.js" import styles from './Button.module.css' @@ -96,7 +98,8 @@ export function Button() { return (