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

13 — Not Found (not-found.js / not-found.tsx)

Výuka

Proč to existuje?

Když uživatel zadá URL, která neexistuje (např. /blog/neexistujici-clanek), nebo když databáze neobsahuje požadovaný záznam, měla by aplikace zobrazit přátelskou 404 stránku místo běžné chyby nebo prázdné stránky.

Not Found stránka (404) informuje uživatele, že hledaný obsah neexistuje, a nabízí mu návrat na fungující části aplikace (např. domovská stránka, vyhledávání).

Jak to funguje?

Next.js poskytuje dva způsoby, jak zobrazit 404 stránku:

1. Automaticky — když Next.js nenajde odpovídající route

  • Uživatel zadá /neexistujici-stranka → zobrazí se root not-found.js

2. Programově — pomocí funkce notFound()

  • Načítáš data z databáze → záznam neexistuje → zavoláš notFound()
  • Next.js zobrazí nejbližší not-found.js v adresářové struktuře

Kde umístit not-found.js:

app/
├─ not-found.js        # globální 404 stránka
├─ page.js
└─ blog/
   ├─ not-found.js     # 404 specifická pro blog sekci
   └─ [slug]/
      └─ page.js

K čemu to slouží?

  • Lepší UX — uživatel ví, že stránka neexistuje (není to chyba aplikace)
  • SEO — správná HTTP 404 odpověď pro vyhledávače
  • Navigace zpět — odkaz na domovskou stránku nebo vyhledávání
  • Branding — možnost udržet design a identitu aplikace i na chybové stránce

JavaScript

// app/not-found.js (globální 404)
import Link from 'next/link'

export default function NotFound() {
  return (
    <div style={{ textAlign: 'center', padding: '4rem 2rem' }}>
      <h1 style={{ fontSize: '4rem', margin: '0' }}>404</h1>
      <h2>Stránka nenalezena</h2>
      <p style={{ color: '#666', marginBottom: '2rem' }}>
        Omlouváme se, ale stránka, kterou hledáte, neexistuje.
      </p>
      <Link href="/" style={{ color: '#0070f3', textDecoration: 'none' }}>
        ← Zpět na domovskou stránku
      </Link>
    </div>
  )
}

Programové vyvolání 404

// app/blog/[slug]/page.js
import { notFound } from 'next/navigation'

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

  // Pokud článek neexistuje, zobraz 404
  if (!post) {
    notFound()
  }

  return (
    <article>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </article>
  )
}

Vlastní 404 pro sekci

// app/blog/not-found.js
import Link from 'next/link'

export default function BlogNotFound() {
  return (
    <div style={{ textAlign: 'center', padding: '2rem' }}>
      <h2>Článek nenalezen</h2>
      <p>Tento článek neexistuje nebo byl odstraněn.</p>
      <Link href="/blog">← Zpět na seznam článků</Link>
    </div>
  )
}

TypeScript

// app/not-found.tsx (globální 404)
import Link from 'next/link'

export default function NotFound(): JSX.Element {
  return (
    <div style={{ textAlign: 'center', padding: '4rem 2rem' }}>
      <h1 style={{ fontSize: '4rem', margin: '0' }}>404</h1>
      <h2>Stránka nenalezena</h2>
      <p style={{ color: '#666', marginBottom: '2rem' }}>
        Omlouváme se, ale stránka, kterou hledáte, neexistuje.
      </p>
      <Link href="/" style={{ color: '#0070f3', textDecoration: 'none' }}>
        ← Zpět na domovskou stránku
      </Link>
    </div>
  )
}

Programové vyvolání s typy

// app/blog/[slug]/page.tsx
import { notFound } from 'next/navigation'

interface Post {
  id: number
  slug: string
  title: string
  content: string
}

interface PageProps {
  params: { slug: string }
}

export default async function BlogPost({ params }: PageProps): Promise<JSX.Element> {
  const response = await fetch(`https://api.example.com/posts/${params.slug}`)

  if (!response.ok) {
    notFound() // Vyvolá nejbližší not-found.tsx
  }

  const post: Post = await response.json()

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

Typovaná 404 s vyhledáváním

// app/products/not-found.tsx
import Link from 'next/link'

export default function ProductNotFound(): JSX.Element {
  return (
    <div style={{ maxWidth: '600px', margin: '4rem auto', textAlign: 'center' }}>
      <h2>Produkt nenalezen</h2>
      <p>Tento produkt neexistuje nebo není skladem.</p>
      <div style={{ marginTop: '2rem', display: 'flex', gap: '1rem', justifyContent: 'center' }}>
        <Link href="/products">
          Procházet produkty
        </Link>
        <Link href="/products/search">
          Vyhledat produkt
        </Link>
      </div>
    </div>
  )
}

Rozdíl JS vs TS

TypeScript přidává typy pro params a searchParams v page komponentách, což zajišťuje, že pracuješ se správnými parametry URL. Také typuje návratové hodnoty komponent (JSX.Element) a datové struktury (např. Post interface).

Důležité poznámky

Funkce notFound()

import { notFound } from 'next/navigation'

// Použití
if (!data) {
  notFound() // Vyvolá nejbližší not-found.js/tsx v adresářové struktuře
}

Kde to použít:

  • Když databázový záznam neexistuje
  • Když uživatel nemá oprávnění (alternativně můžeš použít custom error)
  • Když API vrátí 404

Hierarchie not-found souborů

app/
├─ not-found.js              # Globální 404 (fallback)
├─ products/
  ├─ not-found.js           # 404 pro /products/*
  └─ [id]/page.js           # Pokud zavolá notFound(), použije products/not-found.js
└─ blog/
   ├─ not-found.js           # 404 pro /blog/*
   └─ [slug]/page.js         # Pokud zavolá notFound(), použije blog/not-found.js

Priorita: Next.js použije nejbližší not-found.js v adresářovém stromu směrem nahoru.

Metadata pro 404

// app/not-found.tsx
import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: '404 - Stránka nenalezena',
  description: 'Tato stránka neexistuje'
}

export default function NotFound() {
  // ...
}

Tip

  • Užitečné odkazy — nabídni uživateli cestu zpět (domů, vyhledávání, kontakt)
  • Zachovej design — 404 stránka by měla odpovídat zbytku aplikace (layout, barvy)
  • SEO — Next.js automaticky vrací HTTP 404 status code
  • Logování — v produkci můžeš logovat 404 (trackovat rozbité odkazy)
  • Humor — můžeš použít vtipnou hlášku nebo obrázek (ale zůstaň profesionální)
  • Validace před fetchem — ověř parametry před načítáním dat (např. ID musí být číslo)

Příklad s validací

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

  // Validace: pokud ID není číslo, zobraz 404
  if (isNaN(id) || id <= 0) {
    notFound()
  }

  const product = await getProduct(id)

  if (!product) {
    notFound()
  }

  return <ProductDetail product={product} />
}

Kvíz

Kdy se zobrazí obsah souboru not-found.js?

Not Found stránka se zobrazí dvěma způsoby: (1) Automaticky — když uživatel navštíví URL, která neodpovídá žádné route v aplikaci. Next.js automaticky zobrazí nejbližší not-found.js. (2) Programově — když v kódu zavoláš notFound() funkci (např. když záznam v databázi neexistuje). Chyba 500 se řeší pomocí error.js, ne not-found.js.

Not Found stránka se zobrazí dvěma způsoby: (1) Automaticky — když uživatel navštíví URL, která neodpovídá žádné route v aplikaci. Next.js automaticky zobrazí nejbližší not-found.js. (2) Programově — když v kódu zavoláš notFound() funkci (např. když záznam v databázi neexistuje). Chyba 500 se řeší pomocí error.js, ne not-found.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ě