aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Webontwikkeling

Next.js App Router: de app-map en geneste routes

De Next.js App Router is het routeringssysteem dat stabiel werd in Next.js 13 en de oudere pages/-map vervangt. Door je mappenstructuur rechtstreeks aan URL's te koppelen, brengt het React Server Components, geneste layouts en streaming standaard mee. In deze gids bouwen we stap voor stap, met echte voorbeelden, hoe de app/-map werkt, wat de speciale bestanden doen en hoe geneste routing in elkaar zit.

Waarom bestaat de app-map?

In het oude pages/-systeem was elk bestand een pagina en steunde het ophalen van data op speciale functies zoals getServerSideProps. De App Router is mapgebaseerd: een map is een routesegment en de speciale bestanden erin bepalen het gedrag van dat segment. Het grootste verschil is dat componenten standaard Server Components zijn — ze worden op de server gerenderd zonder JavaScript naar de browser te sturen.

De gezondste manier om een project met de App Router te starten is de officiële opzettool:

npx create-next-app@latest mijn-project
cd mijn-project
npm run dev

De installatiewizard stelt vragen over TypeScript, ESLint en de App Router. Wanneer je de App Router kiest, wordt er een app/-map in de projectroot aangemaakt.

Speciale bestanden: page, layout en de rest

In de App Router maken mappen de route, maar een segment wordt pas echt bereikbaar via bestanden met specifieke namen. De meest voorkomende zijn:

  • page.tsx — rendert de eigenlijke inhoud van het segment en maakt de route publiek toegankelijk.
  • layout.tsx — een omhulsel dat gedeeld wordt over onderliggende segmenten en niet opnieuw wordt gerenderd bij navigatie.
  • loading.tsx — creëert een Suspense-grens; de tussenstand die wordt getoond terwijl data laadt.
  • error.tsx — een component aan de clientzijde die fouten binnen het segment opvangt.
  • not-found.tsx — de 404-interface voor niet-gevonden inhoud.

In zijn eenvoudigste vorm ziet een startpagina er zo uit:

// app/page.tsx
export default function Home() {
  return <h1>Hallo aslain.dev</h1>;
}

De root-layout: een verplicht skelet

app/layout.tsx is verplicht in elk App Router-project omdat het de <html>- en <body>-tags definieert. De root-layout is het buitenste omhulsel dat elke pagina omvat en blijft behouden bij paginaovergangen:

// app/layout.tsx
export const metadata = {
  title: "aslain.dev",
  description: "Portfolio van een veelzijdige ontwikkelaar",
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="nl">
      <body>{children}</body>
    </html>
  );
}

De children-prop vertegenwoordigt de onderliggende pagina of inner-layout die binnen deze layout wordt geplaatst. Dit is de hoeksteen van de geneste structuur.

De logica van geneste routes

Geneste routes maak je door mappen in mappen te plaatsen. Stel dat we een blogsectie bouwen:

app/
  layout.tsx          → root-layout
  page.tsx            → /
  blog/
    layout.tsx        → omvat /blog en lager
    page.tsx          → /blog
    [slug]/
      page.tsx        → /blog/willekeurig-artikel

Hier is [slug] een dynamisch segment. De vierkante haken geven aan dat dit deel uit de URL komt. Je benadert de waarde via params:

// app/blog/[slug]/page.tsx
export default async function Post({
  params,
}: {
  params: Promise<{ slug: string }>;
}) {
  const { slug } = await params;
  return <article>Artikel: {slug}</article>;
}

Sinds Next.js 15 is params nu een Promise en moet het worden ge-await; daarom hebben we het component als async gedeclareerd. Belangrijk punt: blog/layout.tsx omvat zowel /blog als /blog/[slug], maar wordt niet opnieuw gerenderd wanneer de gebruiker van artikel naar artikel gaat. Dit is ideaal om gedeelde elementen zoals een zijbalk of koptekst te behouden.

Server- en clientcomponenten

In de App Router is elk component een Server Component, tenzij anders aangegeven. Waar je interactiviteit nodig hebt (klikken, state, useState, useEffect), plaats je de directive "use client" bovenaan het bestand:

// app/components/Teller.tsx
"use client";
import { useState } from "react";

export default function Teller() {
  const [n, setN] = useState(0);
  return <button onClick={() => setN(n + 1)}>{n}</button>;
}

Een goede strategie is om het grootste deel van de boom als Server Components te houden en alleen de interactieve onderdelen op bladniveau naar de client te halen. Zo houd je de hoeveelheid JavaScript die naar de browser wordt gestuurd tot een minimum beperkt.

Navigeren tussen pagina's

Gebruik om tussen pagina's te schakelen het next/link-component in plaats van een gewone <a>. Het zorgt voor navigatie aan de clientzijde en prefetching:

import Link from "next/link";

export default function Menu() {
  return (
    <nav>
      <Link href="/">Home</Link>
      <Link href="/blog">Blog</Link>
    </nav>
  );
}

Wanneer je programmatische navigatie nodig hebt, haal je de useRouter-hook uit next/navigation binnen clientcomponenten.

Veelgestelde vragen

Kunnen de App Router en de Pages Router in één project samenleven?

Ja. Next.js staat zowel app/- als pages/-mappen op rootniveau toe; dit is bedoeld om bestaande projecten stapsgewijs te migreren. Als dezelfde route in beide is gedefinieerd, heeft app/ voorrang.

Wat gebeurt er als ik een map toevoeg zonder page.tsx?

Een map zonder page.tsx is niet bereikbaar via een URL; die wordt puur voor organisatie gebruikt (bijvoorbeeld routegroepen of gedeelde componenten). Een toegankelijke route vereist altijd een page.tsx.

Waar moet ik data ophalen?

Je kunt async/await met fetch rechtstreeks binnen Server Components gebruiken; speciale functies zoals getServerSideProps zijn niet nodig. Next.js cachet fetch-aanroepen automatisch en hervalideert ze wanneer nodig.

Wil je je Next.js-project correct opzetten of een bestaande applicatie naar de App Router migreren? Ik help je een schone, performante en SEO-vriendelijke architectuur op te bouwen. Neem contact met me op en laten we je project samen plannen.

Bu kategorideki tüm yazılar →

Devamı için