0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Next.jsのparamsとは? - 中学生でもわかる解説

Posted at

paramsって何?

params(パラムス)は、URLから値を取り出すための特別な箱です。

例えば、こんなURLがあったとします:

https://example.com/products/123

この123の部分を取り出して使いたい時に、paramsを使います。

身近な例で理解しよう

YouTubeの動画ページ

https://youtube.com/watch?v=abc123xyz
  • abc123xyzが動画のID
  • YouTubeはこのIDを使って、どの動画を表示するか決める

Amazonの商品ページ

https://amazon.co.jp/dp/B08N5WRWNW
  • B08N5WRWNWが商品のID
  • AmazonはこのIDを使って、商品情報を取得する

Next.jsのparamsも同じことをします!

なぜparamsが必要なの?

問題:同じようなページがたくさんある

例えば、商品が1000個あるECサイトを作るとします。

❌ paramsを使わない場合(大変!)

products/1.jsx     → 商品1のページ
products/2.jsx     → 商品2のページ
products/3.jsx     → 商品3のページ
...
products/1000.jsx  → 商品1000のページ

1000個もファイルを作るの?無理ですよね。

✅ paramsを使う場合(簡単!)

products/[id].jsx  → 全商品に対応

たった1つのファイルで、全ての商品ページを作れます!

paramsの基本的な使い方

1. フォルダ構成

角カッコ[ ]を使ってフォルダを作ります。

app/
  products/
    [id]/
      page.jsx    ← このファイルで全商品に対応

ポイント:

  • [id]の部分が「変わる値」を表す
  • idは好きな名前でOK([productId][slug]など)

2. コードで使う

// app/products/[id]/page.jsx
export default function ProductPage({ params }) {
  return (
    <div>
      <h1>商品ID: {params.id}</h1>
      <p>この商品の詳細ページです</p>
    </div>
  );
}

URLとparamsの対応:

  • /products/1 にアクセス → params.id = "1"
  • /products/999 にアクセス → params.id = "999"
  • /products/abc にアクセス → params.id = "abc"

実際の使用例

例1:商品詳細ページ

// app/products/[id]/page.jsx
export default async function ProductPage({ params }) {
  // paramsからIDを取り出す
  const productId = params.id;
  
  // そのIDで商品データを取得
  const response = await fetch(`https://api.shop.com/products/${productId}`);
  const product = await response.json();
  
  return (
    <div>
      <h1>{product.name}</h1>
      <p>商品番号: {productId}</p>
      <p>価格: {product.price}</p>
      <p>{product.description}</p>
    </div>
  );
}

動作例:

  • /products/123 → 商品123の情報を表示
  • /products/456 → 商品456の情報を表示

例2:ユーザープロフィールページ

// app/users/[username]/page.jsx
export default async function UserPage({ params }) {
  const username = params.username;
  
  const response = await fetch(`https://api.example.com/users/${username}`);
  const user = await response.json();
  
  return (
    <div>
      <h1>@{username}</h1>
      <p>名前: {user.name}</p>
      <p>自己紹介: {user.bio}</p>
      <p>フォロワー: {user.followers}</p>
    </div>
  );
}

動作例:

  • /users/taro → taroさんのプロフィール
  • /users/hanako → hanakoさんのプロフィール

例3:ブログ記事ページ

// app/blog/[slug]/page.jsx
export default async function BlogPost({ params }) {
  const slug = params.slug;
  
  const response = await fetch(`https://api.blog.com/posts/${slug}`);
  const post = await response.json();
  
  return (
    <article>
      <h1>{post.title}</h1>
      <p>投稿日: {post.publishedAt}</p>
      <p>著者: {post.author}</p>
      <div>{post.content}</div>
    </article>
  );
}

動作例:

  • /blog/my-first-post → "my-first-post"の記事
  • /blog/hello-world → "hello-world"の記事

複数のparamsを使う

ネストされたパラメータ

2つ以上のパラメータを使うこともできます。

フォルダ構成:

app/
  shop/
    [category]/
      [productId]/
        page.jsx

コード:

// app/shop/[category]/[productId]/page.jsx
export default async function ProductPage({ params }) {
  const category = params.category;
  const productId = params.productId;
  
  return (
    <div>
      <p>カテゴリ: {category}</p>
      <p>商品ID: {productId}</p>
    </div>
  );
}

URLとparamsの対応:

  • /shop/electronics/123

    • params.category = "electronics"
    • params.productId = "123"
  • /shop/books/456

    • params.category = "books"
    • params.productId = "456"

実用例:カテゴリ別商品ページ

// app/shop/[category]/[productId]/page.jsx
export default async function ProductPage({ params }) {
  const { category, productId } = params;
  
  const response = await fetch(
    `https://api.shop.com/${category}/products/${productId}`
  );
  const product = await response.json();
  
  return (
    <div>
      <nav>
        <a href={`/shop/${category}`}> {category}に戻る</a>
      </nav>
      
      <h1>{product.name}</h1>
      <p>カテゴリ: {category}</p>
      <p>価格: {product.price}</p>
      <button>購入する</button>
    </div>
  );
}

URLの例:

/shop/electronics/smartphone-123
/shop/books/novel-456
/shop/fashion/shoes-789

paramsの型と注意点

paramsは常に文字列

重要:paramsの値は必ず文字列(string)です。

export default function Page({ params }) {
  console.log(params.id);        // "123" (文字列)
  console.log(typeof params.id); // "string"
}

数値として使いたい場合

export default async function Page({ params }) {
  // 文字列を数値に変換
  const id = Number(params.id);
  // または
  const id = parseInt(params.id, 10);
  
  console.log(id);        // 123 (数値)
  console.log(typeof id); // "number"
  
  // 数値として計算できる
  const nextId = id + 1;  // 124
}

例:ページネーション

// app/posts/page/[pageNumber]/page.jsx
export default async function PostsPage({ params }) {
  // 文字列を数値に変換
  const pageNumber = parseInt(params.pageNumber, 10);
  
  // 1ページあたり10件
  const postsPerPage = 10;
  const skip = (pageNumber - 1) * postsPerPage;
  
  const response = await fetch(
    `https://api.blog.com/posts?skip=${skip}&limit=${postsPerPage}`
  );
  const posts = await response.json();
  
  return (
    <div>
      <h1>記事一覧 - ページ {pageNumber}</h1>
      
      {posts.map(post => (
        <article key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.excerpt}</p>
        </article>
      ))}
      
      <nav>
        <a href={`/posts/page/${pageNumber - 1}`}> 前のページ</a>
        <a href={`/posts/page/${pageNumber + 1}`}>次のページ </a>
      </nav>
    </div>
  );
}

paramsのバリデーション(検証)

不正な値が来た時の対処も大切です。

例1:数値チェック

export default async function ProductPage({ params }) {
  const id = params.id;
  
  // 数値かどうかチェック
  if (!/^\d+$/.test(id)) {
    return (
      <div>
        <h1>エラー</h1>
        <p>商品IDは数値である必要があります</p>
      </div>
    );
  }
  
  // 正常処理
  const response = await fetch(`https://api.shop.com/products/${id}`);
  const product = await response.json();
  
  return <div>{product.name}</div>;
}

例2:存在チェック

export default async function UserPage({ params }) {
  const username = params.username;
  
  try {
    const response = await fetch(`https://api.example.com/users/${username}`);
    
    // 404エラーの場合
    if (response.status === 404) {
      return (
        <div>
          <h1>ユーザーが見つかりません</h1>
          <p>@{username} は存在しません</p>
        </div>
      );
    }
    
    const user = await response.json();
    return <div>@{username}のページ</div>;
    
  } catch (error) {
    return <div>エラーが発生しました</div>;
  }
}

例3:許可された値のみ受け付ける

// app/docs/[section]/page.jsx
export default function DocsPage({ params }) {
  const allowedSections = ['getting-started', 'api', 'examples', 'faq'];
  
  // 許可されたセクションかチェック
  if (!allowedSections.includes(params.section)) {
    return (
      <div>
        <h1>ページが見つかりません</h1>
        <p>利用可能なセクション:</p>
        <ul>
          {allowedSections.map(section => (
            <li key={section}>
              <a href={`/docs/${section}`}>{section}</a>
            </li>
          ))}
        </ul>
      </div>
    );
  }
  
  return <div>{params.section}のドキュメント</div>;
}

paramsを使った実践パターン

パターン1:詳細ページのテンプレート

// app/items/[id]/page.jsx
export default async function ItemDetailPage({ params }) {
  try {
    const response = await fetch(`https://api.example.com/items/${params.id}`);
    
    if (!response.ok) {
      return <div>アイテムが見つかりません</div>;
    }
    
    const item = await response.json();
    
    return (
      <div>
        <h1>{item.title}</h1>
        <img src={item.image} alt={item.title} />
        <p>{item.description}</p>
        <p>価格: {item.price}</p>
      </div>
    );
  } catch (error) {
    return <div>エラーが発生しました</div>;
  }
}

パターン2:編集ページ

// app/posts/[id]/edit/page.jsx
export default async function EditPostPage({ params }) {
  const response = await fetch(`https://api.blog.com/posts/${params.id}`);
  const post = await response.json();
  
  return (
    <div>
      <h1>記事を編集</h1>
      <form>
        <input 
          type="text" 
          defaultValue={post.title}
          name="title"
        />
        <textarea 
          defaultValue={post.content}
          name="content"
        />
        <button type="submit">保存</button>
      </form>
    </div>
  );
}

パターン3:関連ページへのリンク

// app/products/[id]/page.jsx
export default async function ProductPage({ params }) {
  const productId = params.id;
  
  const [product, reviews] = await Promise.all([
    fetch(`https://api.shop.com/products/${productId}`).then(r => r.json()),
    fetch(`https://api.shop.com/products/${productId}/reviews`).then(r => r.json())
  ]);
  
  return (
    <div>
      <h1>{product.name}</h1>
      <p>{product.description}</p>
      
      {/* 関連ページへのリンク */}
      <nav>
        <a href={`/products/${productId}`}>詳細</a>
        <a href={`/products/${productId}/reviews`}>レビュー</a>
        <a href={`/products/${productId}/specs`}>仕様</a>
      </nav>
      
      <section>
        <h2>レビュー ({reviews.length})</h2>
        {reviews.map(review => (
          <div key={review.id}>
            <p> {review.rating}/5</p>
            <p>{review.comment}</p>
          </div>
        ))}
      </section>
    </div>
  );
}

メタデータでもparamsを使える

ページのタイトルや説明文を動的に変えられます。

基本的な使い方

// app/products/[id]/page.jsx

// メタデータを動的に生成
export async function generateMetadata({ params }) {
  const response = await fetch(`https://api.shop.com/products/${params.id}`);
  const product = await response.json();
  
  return {
    title: `${product.name} - オンラインショップ`,
    description: product.description
  };
}

// ページコンポーネント
export default async function ProductPage({ params }) {
  const response = await fetch(`https://api.shop.com/products/${params.id}`);
  const product = await response.json();
  
  return (
    <div>
      <h1>{product.name}</h1>
      <p>{product.description}</p>
    </div>
  );
}

効果:

  • ブラウザのタブに商品名が表示される
  • Google検索結果に適切な情報が表示される
  • SNSでシェアした時にきれいに表示される

SEO対策の例

// app/articles/[slug]/page.jsx

export async function generateMetadata({ params }) {
  const article = await fetch(
    `https://api.blog.com/articles/${params.slug}`
  ).then(r => r.json());
  
  return {
    title: article.title,
    description: article.excerpt,
    keywords: article.tags.join(', '),
    openGraph: {
      title: article.title,
      description: article.excerpt,
      images: [article.coverImage],
      type: 'article',
      publishedTime: article.publishedAt,
      authors: [article.author.name]
    },
    twitter: {
      card: 'summary_large_image',
      title: article.title,
      description: article.excerpt,
      images: [article.coverImage]
    }
  };
}

export default async function ArticlePage({ params }) {
  const article = await fetch(
    `https://api.blog.com/articles/${params.slug}`
  ).then(r => r.json());
  
  return (
    <article>
      <h1>{article.title}</h1>
      <img src={article.coverImage} alt={article.title} />
      <div>{article.content}</div>
    </article>
  );
}

静的生成でparamsを使う

generateStaticParams を使う

ビルド時に全てのページを事前生成できます。

// app/products/[id]/page.jsx

// どのIDのページを生成するか指定
export async function generateStaticParams() {
  const response = await fetch('https://api.shop.com/products');
  const products = await response.json();
  
  // [{id: '1'}, {id: '2'}, {id: '3'}, ...] を返す
  return products.map(product => ({
    id: product.id.toString()
  }));
}

// ページコンポーネント
export default async function ProductPage({ params }) {
  const response = await fetch(`https://api.shop.com/products/${params.id}`);
  const product = await response.json();
  
  return <div>{product.name}</div>;
}

メリット:

  • ページが超高速(HTMLが事前に作られている)
  • サーバー負荷が少ない

いつ使う?

  • 商品数が決まっている
  • 記事数が多くない
  • 頻繁に更新されない

例:ブログの記事一覧

// app/blog/[slug]/page.jsx

export async function generateStaticParams() {
  // 全記事のslugを取得
  const posts = await fetch('https://api.blog.com/posts').then(r => r.json());
  
  return posts.map(post => ({
    slug: post.slug
  }));
}

export default async function BlogPost({ params }) {
  const post = await fetch(
    `https://api.blog.com/posts/${params.slug}`
  ).then(r => r.json());
  
  return (
    <article>
      <h1>{post.title}</h1>
      <div>{post.content}</div>
    </article>
  );
}

よくある質問

Q1: paramsとsearchParamsの違いは?

params: URLのパス部分から取得

/products/123
         ^^^
    これがparams

searchParams: URLのクエリ文字列から取得

/search?q=smartphone&sort=price
        ^^^^^^^^^^^^^^^^^^^^^^^
       これがsearchParams

使い分け:

// app/products/[id]/page.jsx
export default function ProductPage({ params, searchParams }) {
  const productId = params.id;           // 123
  const sortBy = searchParams.sort;      // "price"
  const query = searchParams.q;          // "smartphone"
  
  return <div>商品 {productId}</div>;
}

Q2: paramsが取得できない時は?

チェック項目:

  1. フォルダ名が[名前]になっているか
  2. page.jsxファイルが正しい場所にあるか
  3. 関数の引数に{ params }を書いているか
// ❌ これは動かない
export default function Page(params) {
  return <div>{params.id}</div>;
}

// ✅ これが正しい
export default function Page({ params }) {
  return <div>{params.id}</div>;
}

Q3: paramsは必須?

A: いいえ、動的ルーティングを使わないページでは不要です。

// app/about/page.jsx - paramsなし
export default function AboutPage() {
  return <div>会社概要</div>;
}

// app/products/[id]/page.jsx - paramsあり
export default function ProductPage({ params }) {
  return <div>商品 {params.id}</div>;
}

Q4: 日本語のURLは使える?

A: 使えますが、エンコードされます。

// app/blog/[slug]/page.jsx
export default function BlogPost({ params }) {
  console.log(params.slug);
  // URLが /blog/こんにちは の場合
  // params.slug = "こんにちは"
  
  return <div>{params.slug}</div>;
}

注意:
URLとしては%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AFのようにエンコードされますが、Next.jsが自動でデコードしてくれます。

よくある間違い

間違い1: paramsを直接変更しようとする

// ❌ これはエラー
export default function Page({ params }) {
  params.id = "999"; // paramsは読み取り専用!
  return <div>{params.id}</div>;
}

// ✅ 新しい変数に入れる
export default function Page({ params }) {
  const id = params.id;
  const modifiedId = id + "-modified";
  return <div>{modifiedId}</div>;
}

間違い2: paramsの存在を確認しない

// ❌ paramsがない場合にエラー
export default function Page({ params }) {
  return <div>{params.id.toUpperCase()}</div>;
}

// ✅ 存在確認をする
export default function Page({ params }) {
  if (!params.id) {
    return <div>IDが指定されていません</div>;
  }
  
  return <div>{params.id.toUpperCase()}</div>;
}

間違い3: awaitを忘れる

// ❌ paramsがPromiseになってしまう
export default function Page({ params }) {
  // Next.js 15以降、paramsは非同期
  return <div>{params.id}</div>; // [object Promise]と表示される
}

// ✅ asyncをつけてawaitする
export default async function Page({ params }) {
  const resolvedParams = await params; // Next.js 15以降
  return <div>{resolvedParams.id}</div>;
}

注意:
Next.js 15以降では、paramsが非同期になる場合があります。最新のドキュメントを確認してください。

まとめ

paramsの本質

paramsは、URLから値を取り出して使うための仕組み

  • 1つのファイルで複数のページに対応できる
  • URLの値に応じてデータを取得できる
  • 動的なWebサイトを作るのに必須

基本の型

// app/[パラメータ名]/page.jsx
export default async function Page({ params }) {
  const value = params.パラメータ名;
  
  // この値を使ってデータ取得など
  const data = await fetch(`API/${value}`);
  
  return <div>{data.name}</div>;
}

覚えておくこと

  1. フォルダ名を[名前]にする

    • この名前がparamsのキーになる
  2. paramsは常に文字列

    • 数値として使う時は変換が必要
  3. エラー処理を忘れずに

    • 不正な値が来ることも考える
  4. 複数のparamsも使える

    • ネストしたフォルダで実現

最も大事なこと:
paramsを使えば、1つのファイルで無限のページを作れる!これがNext.jsの動的ルーティングの力です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?