Topics

Next.js Pages Router en App Router: de verschillen die vaak door elkaar lopen, op een rij gezet

  • column

Next.js, een webontwikkelingsframework dat veel steun geniet, introduceerde in versie 13 de App Router als het nieuwe standaard routeringssysteem.

Wie aan projecten met zowel de Pages Router als de App Router werkt, raakt wel eens in de war over welke schrijfwijze waarvoor geldt. Ik ben daar zelf een goed voorbeeld van!

Met name op het gebied van de kern van applicatieontwikkeling zijn er belangrijke verschillen tussen de Pages Router en de App Router. Denk aan de manier waarop routes worden gedefinieerd op basis van de bestandsstructuur, de verwerking van dynamische URL-onderdelen, de werking van rendering en het ophalen van data via de API.

Hieronder vind je, kort samengevat als geheugensteun, de belangrijkste verschillen tussen de Pages Router en de App Router, met de nadruk op de punten die vaak door elkaar lopen.

Verschillen in bestandsgebaseerde routering

Pages Router: eenvoud doordat de bestandsnaam direct het pad wordt

De eenvoud zit in het feit dat de bestandsnaam van bestanden in de map pages, zoals .js, .jsx, .ts en .tsx, rechtstreeks het URL-pad wordt.

Voorbeeld: src/page/about.tsx ⇒ de route wordt /about.

App Router: structuur op basis van mappen en specifieke bestandsnamen

In de App Router kun je routes maken door mappen en bestanden te plaatsen in src/app.

Een bestand met de specifieke naam page is echter de inhoud van de pagina die bij dat pad hoort.

Voorbeeld: src/app/about/page.tsx ⇒ de route wordt /about.

De "speciale bestanden" die de App Router kenmerken

Daarnaast zijn er in de App Router ook andere bestanden dan page.tsx die een specifieke betekenis hebben.

app/
├── page.tsx           --> ページの中身。これが一番よく使うファイル
├── route.tsx          --> APIの定義(page.jsと共存不可)
├── layout.tsx         --> 共通の見た目
├── loading.tsx        --> 読み込み中の画面
├── error.tsx          --> エラー時の画面
├── global-error.tsx   --> グローバルエラー画面
├── templete.tsx       --> 共通の見た目(リセットされるレイアウト)
├── default.tsx        --> デフォルトの画面
└── not-found.tsx      --> notFound関数がスローされたときの画面

Wat me persoonlijk het meest verraste was not-found.tsx. Alleen al door deze pagina aan te maken, wordt er automatisch een pagina getoond wanneer er een niet-bestaande URL wordt bezocht. Dat het zo eenvoudig te implementeren is, verbaasde me.

Verschillen in rendering

Componenten in de Pages Router zijn in principe bedoeld om aan de clientzijde interactief te zijn. Server-side rendering wordt voornamelijk gebruikt om de initiële weergave te versnellen en voor SEO. React-hooks zoals useState en useEffect kunnen vrij worden gebruikt binnen paginacomponenten en hun childcomponenten.

Componenten binnen app/ in de App Router worden daarentegen standaard behandeld als servercomponenten, tenzij expliciet anders is opgegeven. Daarom kunnen useState en useEffect niet worden gebruikt, en React-hooks zijn niet beschikbaar. Ook clientzijde acties zoals onClick en event handlers kunnen niet worden gebruikt.

Om in de App Router een CSR-component te maken, schrijf je use client.

use client

Dit is de grensdefinitie tussen Server Components en Client Components. Wanneer je use client declareert, worden niet alleen die component, maar ook alle modules die daarin worden geïmporteerd, als Client Component beschouwd.

Dynamische routing [○○]

Dynamische routing in Next.js is het mechanisme dat zorgt voor "dynamische URL's", waarbij een deel van de URL varieert op basis van gebruikers of content, zoals bij detailpagina's van blogs of nieuwsartikelen. Dit mechanisme wordt dynamische routing genoemd.

Stel dat er een link is die naar artikel A en een link die naar artikel B verwijst.

Bijvoorbeeld een schermafbeelding van een pagina met links naar artikel A en artikel B
import Link from "next/link";
const linkStyle=`ext-lg font-bold border-b border-primary px-1`

export default function page() {
  return (
    <div>
      <div className="flex gap-6">
        <Link href="/post/A" className={linkStyle}>記事Aへのリンク</Link>
        <Link href="/post/B" className={linkStyle}>記事Bへのリンク</Link>
      </div>
    </div>
  );
}

De bestemming van elke link

Schermafbeelding van de pagina post/A
Schermafbeelding van de pagina post/B

Bij dynamische routing maak je een bestand aan met de naam [slug]. Daarmee kun je dezelfde template gebruiken voor post/A en post/B.
*De naam tussen [ ] is vrij te kiezen, dus het hoeft niet slug te zijn.

Bij App Router

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

export default aysinc function PostPage({ params }: { params: Promise<{ slug: string }>) {
  const {slug}= await params;
  return (
    <div>
      <h1>記事: {slug}</h1>
    </div>
  );
}

Gebruik params. params.slug bevat het deel [slug] van de URL.

* Het ophalen van parameters via params hoefde vroeger niet asynchroon te zijn, maar vanaf Next.js 15 is dit gewijzigd naar asynchroon. Daarom lijkt het nodig om props als Promise-type te definiëren.

Bij Pages Router

/pages/post/[slug].tsx


import { useRouter } from 'next/router';

export default function PostPage() {
  const router = useRouter();
  const { slug } = router.query;

  return (
    <div>
      <h1>記事: {slug}</h1>
    </div>
  );
}

Gebruik useRouter. In router.query.slug komt de waarde terecht van het [slug]-gedeelte van de URL.

Hoe je API-data ophaalt

microCMS, dat ook in deze Liberogic-column succesvol wordt gebruikt, werkt goed samen met frameworks zoals Next.js.

Bij App Router

Gebruik eenvoudig fetch en async await.

Let op: een bestand waarin use client is gedeclareerd, wordt client-side gerenderd (CSR), waardoor async await niet meer kan worden gebruikt!


async function getPost() {
  const res = await fetch(`https://.../api/data/`);

  // エラーハンドリング例
  if (!res.ok) {
     throw new Error(`Failed to fetch post: ${res.status}`);
  }

  return res.json();
}

Aanroepende functie

export default function Example() {
   const data = await getPost()
   // ... data を使って表示 ...
}

Bij Pages Router

Gebruik getStaticProps en geef de opgehaalde data als props door aan de paginacomponent.


export async function getServerSideProps(context) {
  // context.req, context.res などにアクセス可能
  const res = await fetch(`https://.../api/data/`, {
     headers: { Cookie: context.req.headers.cookie } // 例: Cookieを渡す
  });
  const data = await res.json();

  return {
    props: {
      data,
    },
  };
}

Aanroepende functie

export default function Example({ data }) {
  // ... data を使って表示 ...
}

Begrijp de twee routers en leer Next.js goed gebruiken!

In mijn geval was het eerste project waarin ik met Next.js werkte een project met de App Router.

Daarna werkte ik bij een ander project met de Pages Router, en toen wist ik even niet meer of je voor een nieuwe pagina index.tsx of page.tsx moest gebruiken.

Dit artikel behandelt slechts een klein deel van Next.js, maar door de verschillen tussen de App Router en de Pages Router opnieuw uit te zoeken, heb ik zelf ook wat meer overzicht gekregen.

Persoonlijk vind ik de schrijfwijze van de App Router overzichtelijk en prettig, maar ik wil ook bij projecten met de Pages Router goed kunnen werken.

Het ideaal is om Next.js beter te begrijpen en per project of ontwerp te kunnen kiezen welke router het beste past!

Over de auteur

Ik ben voornamelijk bezig met markup en frontend-ontwikkeling met JavaScript, React en Next.js. Ik ben blij wanneer een site waar ik aan heb meegewerkt succesvol live gaat! Mijn hobby's zijn gitaar spelen. Ik hou van katten en geroosterde zoete aardappel 🐱🍠

ひらっち

Frontend-engineer / in dienst sinds 2022

Bekijk de artikelen van deze medewerker

Ons grootste pluspunt is een betrouwbaar team en een snelle reactie

Bij Liberogic wordt er door onze ervaren medewerkers proactief aan projecten gewerkt, waardoor klanten ons hoog waarderen.
We zorgen ervoor dat er zorgvuldig een projectmanager en een director worden toegewezen, zodat het gehele project soepel verloopt. We voorkomen onnodige kostenstijging door middel van volledige inzet en verdelen de middelen op een manier die past bij de taak. Ook staan we bekend om ons snelle inzicht in de werkzaamheden en het snel opstellen en indienen van offertes.

* Liberogic zet zich niet in voor SES-achtige detacheringsopdrachten op locatie bij klanten. Houd hier alstublieft rekening mee.

U kunt vrijwel alle belangrijke tools voor projectmanagement en chat gebruiken, waaronder Slack, Teams, Redmine, Backlog, Asana, Jira, Notion, Google Workspace, Zoom, Webex en meer.

Bij grootschalige projecten met SES of offshore-ontwikkeling heeft u misschien vragen over technische uitdagingen en de aanpak daarvan?

Casestudies