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

08 — Link komponenta (navigace)

Výuka

Proč to existuje?

V tradičních webových stránkách se používá pro odkazy. Problém je, že každý klik reloaduje celou stránku — prohlížeč stáhne nové HTML, CSS, JavaScript, znovu spustí skripty... To je pomalé a působí "old-school".

Moderní webové aplikace (SPA - Single Page Applications) chtějí rychlé přechody bez reloadu. Next.js poskytuje komponentu , která umožňuje client-side navigation — přechod mezi stránkami je okamžitý, bez reloadu.

Jak to funguje?

Komponenta Link z next/link:

  1. Vypadá jako odkaz, ale chová se jako moderní navigace
  2. Při kliknutí neloaduje celou stránku — jen mění obsah
  3. Automaticky přednačítá cílovou stránku (když je odkaz viditelný)
  4. Zachovává stav aplikace (např. otevřené menu zůstane otevřené)

Důležité:

K čemu to slouží?

JavaScript

// components/Nav.js
import Link from 'next/link'

export default function Nav(){
  return (
    <nav>
      <Link href="/">Domů</Link>
      <Link href="/about">O nás</Link>
      <Link href="/blog">Blog</Link>
      <Link href="/contact">Kontakt</Link>
    </nav>
  )
}

// Pro externí odkazy použij <a>
export default function ExternalLinks(){
  return (
    <div>
      <Link href="/internal">Interní odkaz (používá Link)</Link>
      <a href="https://google.com" target="_blank" rel="noopener noreferrer">
        Google (externí, používá a)
      </a>
    </div>
  )
}
import Link from 'next/link'

export default function ProductList({ products }){
  return (
    <ul>
      {products.map(product => (
        <li key={product.id}>
          <Link href={`/products/${product.id}`}>
            {product.name}
          </Link>
        </li>
      ))}
    </ul>
  )
}

Programová navigace (imperativní)

"use client"

import { useRouter } from 'next/navigation'

export default function SearchForm(){
  const router = useRouter()

  function handleSubmit(e){
    e.preventDefault()
    const query = new FormData(e.target).get('q')
    // Přesměruj na stránku s výsledky
    router.push(`/search?q=${encodeURIComponent(query)}`)
  }

  return (
    <form onSubmit={handleSubmit}>
      <input name="q" placeholder="Hledat..." />
      <button type="submit">Hledat</button>
    </form>
  )
}

TypeScript

import Link from 'next/link'

export default function Nav(): JSX.Element{
  return (
    <nav>
      <Link href="/">Domů</Link>
      <Link href="/about">O nás</Link>
      <Link href="/blog">Blog</Link>
    </nav>
  )
}

// Programová navigace s typy
"use client"

import { useRouter } from 'next/navigation'
import type { FormEvent } from 'react'

export default function SearchForm(): JSX.Element{
  const router = useRouter()

  function handleSubmit(e: FormEvent<HTMLFormElement>){
    e.preventDefault()
    const formData = new FormData(e.currentTarget)
    const query = String(formData.get('q') || '')
    router.push(`/search?q=${encodeURIComponent(query)}`)
  }

  return (
    <form onSubmit={handleSubmit}>
      <input name="q" placeholder="Hledat..." />
      <button type="submit">Hledat</button>
    </form>
  )
}

Rozdíl JS vs TS

TypeScript přidává typy pro:

  • Event handlery (FormEvent)
  • Router metody (useRouter() má typované metody push, replace, atd.)
  • Props pro vlastní Link komponenty

Programová navigace - useRouter API

"use client"

import { useRouter } from 'next/navigation'

export default function NavigationExample(){
  const router = useRouter()

  return (
    <div>
      {/* Push - přidá nový záznam do historie */}
      <button onClick={() => router.push('/dashboard')}>
        Jdi na Dashboard
      </button>

      {/* Replace - nahradí aktuální záznam (nelze se vrátit zpět) */}
      <button onClick={() => router.replace('/login')}>
        Jdi na Login (nahraď historii)
      </button>

      {/* Back - zpět v historii */}
      <button onClick={() => router.back()}>
        Zpět
      </button>

      {/* Forward - vpřed v historii */}
      <button onClick={() => router.forward()}>
        Vpřed
      </button>

      {/* Refresh - znovu načte aktuální route */}
      <button onClick={() => router.refresh()}>
        Refresh
      </button>
    </div>
  )
}

Kdy použít co:

  • router.push() — normální navigace (např. po kliknutí na tlačítko)
  • router.replace() — po úspěšném odeslání formuláře (zabráníš duplicitnímu odeslání)
  • router.back() — tlačítko "Zpět"
  • router.refresh() — znovu načti data (např. po změně v databázi)

Prefetch (přednačítání)

import Link from 'next/link'

// Výchozí - prefetch zapnutý
<Link href="/about">O nás</Link>

// Vypnout prefetch (pro velké stránky nebo citlivá data)
<Link href="/dashboard" prefetch={false}>
  Dashboard
</Link>

Jak funguje prefetch:

  • Link který je viditelný na stránce = Next.js přednačte cílovou stránku na pozadí
  • Když uživatel klikne = stránka se zobrazí okamžitě (už je v cache)
  • Pro produkční build = automaticky zapnuté
  • Pro development = vypnuté (aby se nereloadovaly změny)

Bezpečnost externích odkazů

// ❌ NEBEZPEČNÉ - umožňuje window.opener útok
<a href="https://example.com" target="_blank">
  Externí odkaz
</a>

// ✅ BEZPEČNÉ - rel="noopener noreferrer"
<a href="https://example.com" target="_blank" rel="noopener noreferrer">
  Externí odkaz
</a>

Proč je to důležité:

  • target="_blank" otevře nové okno
  • Bez rel="noopener" může cílová stránka manipulovat s původní stránkou
  • noreferrer skryje, odkud uživatel přišel (privacy)

Tip

Styling odkazů

import Link from 'next/link'

// S CSS třídou
<Link href="/about" className="text-blue-500 hover:underline">
  O nás
</Link>

// S inline styly
<Link href="/about" style={{ color: 'blue', textDecoration: 'none' }}>
  O nás
</Link>

// S aktivním stavem (pomocí usePathname)
"use client"

import { usePathname } from 'next/navigation'
import Link from 'next/link'

export default function NavLink({ href, children }){
  const pathname = usePathname()
  const isActive = pathname === href

  return (
    <Link
      href={href}
      className={isActive ? 'active' : ''}
      style={{ fontWeight: isActive ? 'bold' : 'normal' }}
    >
      {children}
    </Link>
  )
}

🎯 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ě