Domů O mně Služby Portfolio Učím Blog Kontakt
← Zpět na učím

07 — Dynamické routy ([id]/page.js)

Výuka

Proč to existuje?

Pokud máš blog se 100 články, nechceš vytvářet 100 samostatných souborů (clanek-1/page.js, clanek-2/page.js, atd.). Potřebuješ jednu šablonu, která funguje pro všechny články — mění se jen ID nebo slug v URL.

Dynamické routy umožňují vytvořit jednu page komponentu, která obslouží neomezeně mnoho URL s různými parametry.

Jak to funguje?

V Next.js vytvoříš dynamickou routu pomocí hranatých závorek [parametr] v názvu složky:

  • app/blog/[slug]/page.js → obslouží /blog/prvni-clanek, /blog/druhy-clanek, atd.
  • app/products/[id]/page.js → obslouží /products/1, /products/2, /products/999, atd.

Next.js automaticky:

  1. Zachytí parametr z URL (např. slug nebo id)
  2. Předá ho page komponentě jako prop params
  3. Ty použiješ parametr k načtení správných dat

K čemu to slouží?

  • Škálovatelnost — jedna komponenta pro tisíce stránek
  • DRY princip — nepotřebuješ opakovat kód
  • Databázově řízený obsah — načteš data podle ID z URL
  • SEO friendly — každý článek má vlastní URL

JavaScript

// app/blog/[slug]/page.js
export default function BlogPost({ params }) {
  // params.slug obsahuje hodnotu z URL
  // Například: /blog/muj-prvni-clanek → params.slug === "muj-prvni-clanek"

  return (
    <article>
      <h1>Článek: {params.slug}</h1>
      <p>Tady bude obsah článku...</p>
    </article>
  )
}

// app/products/[id]/page.js
export default async function ProductPage({ params }) {
  // Načteme data z API podle ID
  const product = await fetch(`https://api.example.com/products/${params.id}`)
    .then(res => res.json())

  return (
    <div>
      <h1>{product.name}</h1>
      <p>Cena: {product.price} Kč</p>
      <p>{product.description}</p>
    </div>
  )
}

Více dynamických parametrů

// app/users/[userId]/posts/[postId]/page.js
export default function UserPost({ params }) {
  // params.userId a params.postId
  // URL: /users/123/posts/456

  return (
    <div>
      <h1>Příspěvek #{params.postId}</h1>
      <p>od uživatele #{params.userId}</p>
    </div>
  )
}

TypeScript

// app/blog/[slug]/page.tsx
interface PageProps {
  params: { slug: string }
}

export default function BlogPost({ params }: PageProps): JSX.Element {
  return (
    <article>
      <h1>Článek: {params.slug}</h1>
      <p>Tady bude obsah článku...</p>
    </article>
  )
}

// app/products/[id]/page.tsx
interface Product {
  id: number
  name: string
  price: number
  description: string
}

interface PageProps {
  params: { id: string }
}

export default async function ProductPage({ params }: PageProps): Promise<JSX.Element> {
  const product: Product = await fetch(`https://api.example.com/products/${params.id}`)
    .then(res => res.json())

  return (
    <div>
      <h1>{product.name}</h1>
      <p>Cena: {product.price} </p>
      <p>{product.description}</p>
    </div>
  )
}

Více parametrů s typy

interface PageProps {
  params: {
    userId: string
    postId: string
  }
}

export default function UserPost({ params }: PageProps): JSX.Element {
  return (
    <div>
      <h1>Příspěvek #{params.postId}</h1>
      <p>od uživatele #{params.userId}</p>
    </div>
  )
}

Rozdíl JS vs TS

TypeScript přidává typy pro params prop, což zajišťuje:

  • Autocomplete v editoru (víš, jaké parametry máš k dispozici)
  • Type safety — nemůžeš omylem použít neexistující parametr
  • Dokumentaci — ostatní vývojáři ihned vidí, jaké parametry stránka přijímá

generateStaticParams (pro statické generování)

Pro staticky generované stránky (např. všechny články předem) použij generateStaticParams:

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

// Vygeneruje statické stránky při buildu
export async function generateStaticParams() {
  const posts = await fetch('https://api.example.com/posts').then(r => r.json())

  return posts.map((post) => ({
    slug: post.slug,
  }))
}

export default async function BlogPost({ params }: { params: { slug: string } }) {
  const post = await fetch(`https://api.example.com/posts/${params.slug}`)
    .then(r => r.json())

  return (
    <article>
      <h1>{post.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: post.content }} />
    </article>
  )
}

Co to dělá:

  • Při buildu Next.js zavolá generateStaticParams
  • Získá seznam všech slugů
  • Vygeneruje HTML pro každý článek předem
  • Výsledek: ultrarychlé načítání (static HTML bez serveru)

Tip

  • Pojmenování parametru — používej popisné názvy (slug, id, userId, ne jen param)
  • Validace — ověř, že parametr má správný formát (např. ID je číslo)
  • 404 handling — pokud záznam neexistuje, použij notFound() z next/navigation
  • URL encoding — parametry jsou automaticky URL decoded (např. hello%20worldhello world)

Příklad s validací a 404

import { notFound } from 'next/navigation'

export default async function ProductPage({ params }: { params: { id: string } }) {
  const id = parseInt(params.id)

  // Validace: ID musí být číslo
  if (isNaN(id) || id <= 0) {
    notFound()
  }

  const product = await fetch(`https://api.example.com/products/${id}`)
    .then(res => res.ok ? res.json() : null)

  // Pokud produkt neexistuje, zobraz 404
  if (!product) {
    notFound()
  }

  return <div>{product.name}</div>
}

Dynamické segmenty — ASCII diagram

Jak vypadají složky pro dynamické routy:

app/
├─ blog/
  ├─ page.js            # → /blog (seznam článků)
  └─ [slug]/
     └─ page.js         # → /blog/prvni-clanek, /blog/druhy-clanek

├─ products/
  ├─ page.js            # → /products (seznam produktů)
  └─ [id]/
     └─ page.js         # → /products/1, /products/2, /products/999

└─ users/
   └─ [userId]/
      ├─ page.js         # → /users/123
      └─ posts/
         └─ [postId]/
            └─ page.js   # → /users/123/posts/456

Jak to funguje:

  • Hranaté závorky [parametr] = dynamický segment
  • Hodnota z URL se předá jako params.parametr
  • Můžeš mít více dynamických segmentů ve stejné cestě

Kvíz

Jak vytvoříš dynamický segment pro ID produktu v URL /products/123?

V Next.js vytváříš dynamické segmenty pomocí hranatých závorek [parametr] v názvu složky. Například app/products/[id]/page.js vytvoří dynamickou routu, která obslouží /products/1, /products/2, atd. Hodnota z URL (např. 123) se automaticky předá page komponentě jako params.id. Syntaxe :id nebo {id} se používá v jiných frameworcích, ale ne v Next.js.

🎯 Závěrečný projekt

Po dokončení všech 8 dílů vytvoříte jednoduchou Todо aplikaci v čistém JavaScriptu. Naučíte se, jak aplikovat vše, co jste se naučili, na reálný projekt.

Zobrazit podrobnosti projektu →

Připraveni začít?

Zaregistrujte se a získejte přístup ke všem dílům tohoto seriálu

Kontaktujte mě

Informace o seriálu

Obtížnost

Délka

Cca 480 minut

Počet videí

8 videí + projekty

Certifikát

Po dokončení obdržíte certifikát


Lekce v této sekci


Struktura lekcí (souborový strom)

06. Typescript specifika
  • v přípravě
08. Moduly tridy
  • v přípravě
09. React zaklady
  • v přípravě
10. React hooks
  • v přípravě
12. Nextjs server
  • v přípravě
13. Databaze auth
  • v přípravě
14. Nextjs pokrocile
  • v přípravě