Kom igång med App Router
En praktisk guide till Next.js App Router: filbaserad routing, layouts, server- och klientkomponenter, datahämtning, dynamiska rutter, laddningstillstånd och felhantering steg för steg.
Vad är App Router?
App Router är Next.js standardsätt att hantera routing sedan version 13. I stället för att lägga sidor i en pages/-mapp använder du app/-mappen. Varje undermapp motsvarar ett segment i URL:en och varje page.js blir en sida som besökaren kan nå.
Skillnaden mot den äldre Pages Router är inte bara strukturell. App Router bygger på React Server Components som standard. Komponenter renderas på servern och bara den JavaScript som faktiskt behövs i webbläsaren skickas dit. Det förändrar hur du hämtar data, hur du delar upp koden och var dina hemligheter får finnas.
Filstruktur och routing
Routing i App Router är helt filsystembaserad. En fil på app/produkter/page.js svarar på URL:en /produkter. En fil på app/produkter/[id]/page.js svarar på /produkter/123, /produkter/abc och alla andra värden i det dynamiska segmentet.
Varje mapp kan innehålla några speciella filer med bestämda roller:
page.js: sidan som renderas för besökarenlayout.js: ett omslag som delas av sidan och alla undersidorloading.js: visas med React Suspense medan sidan laddarerror.js: visas om ett oväntat fel uppstårnot-found.js: visas när du anroparnotFound()eller när ingen rutt matcharroute.js: en API-endpoint i stället för en sida, se guiden om Route Handlers
Bara page.js och route.js gör en mapp nåbar. En mapp med enbart komponenter eller hjälpfiler syns inte i URL-strukturen, så du kan placera kod nära rutten som använder den.
Vill du gruppera rutter utan att det syns i URL:en sätter du parenteser runt mappnamnet: app/(marknad)/om-oss/page.js svarar fortfarande på /om-oss. Det är praktiskt när olika delar av sajten ska ha olika layouts.
Rotlayouten
Varje projekt måste ha en app/layout.js. Den renderar <html> och <body> och är det enda stället där de taggarna får finnas. Här lägger du typsnitt, global CSS och sådant som ska finnas på varje sida, som navigation och sidfot.
import "./globals.css";
export const metadata = {
title: "Mitt företag",
description: "Vad vi gör och hur du når oss.",
};
export default function RootLayout({ children }) {
return (
<html lang="sv">
<body>
<Navigation />
<main>{children}</main>
<Sidfot />
</body>
</html>
);
}Exporten metadata är Next.js sätt att sätta <title>, beskrivning och Open Graph-taggar. En sida kan exportera sin egen metadata och skriver då över fälten från layouten. Behöver titeln bero på data använder du generateMetadata i stället, vilket vi kommer till.
Layouts och nästling
En av App Routers starkaste funktioner är nästlade layouts. Skapa en layout.js i en mapp, och den omsluter automatiskt alla sidor i den mappen och djupare.
export default function ProduktLayout({ children }) {
return (
<div>
<ProduktNav />
{children}
</div>
);
}Vid navigation mellan två produktsidor renderas bara det som ändrats. Layouten ligger kvar monterad, så en sökruta i ProduktNav behåller sitt värde när besökaren klickar vidare. Det gör också att du inte ska lägga data som är specifik för en enskild sida i layouten, eftersom den inte renderas om vid varje byte.
Server- och klientkomponenter
Alla komponenter i app/ är serverkomponenter tills du säger något annat. De kan vara async, läsa direkt från en databas eller ett API och skicka färdig HTML till webbläsaren. De kan däremot inte använda useState, useEffect eller eventhanterare som onClick.
Behöver en komponent interaktivitet lägger du "use client" överst i filen. Då skickas komponentens kod till webbläsaren.
"use client";
import { useState } from "react";
export default function Raknare() {
const [antal, setAntal] = useState(0);
return (
<button type="button" onClick={() => setAntal(antal + 1)}>
Klickad {antal} gånger
</button>
);
}Tumregeln: håll "use client" så långt ner i trädet som möjligt. En sida kan vara en serverkomponent som hämtar data och sedan renderar en liten klientkomponent för just den del som behöver reagera på klick. Två fel som nästan alla gör i början, och som har egna sidor i vår lista över felmeddelanden, är att anropa useState i en serverkomponent och att skicka en funktion som prop från server till klient.
Hämta data i en sida
Eftersom sidor är serverkomponenter kan de hämta data direkt, utan useEffect och utan en separat API-rutt.
export default async function ProdukterPage() {
const res = await fetch("https://api.exempel.se/produkter");
const produkter = await res.json();
return (
<ul>
{produkter.map((p) => (
<li key={p.id}>{p.namn}</li>
))}
</ul>
);
}Koden körs bara på servern. API-nycklar i miljövariabler utan prefixet NEXT_PUBLIC_ når aldrig webbläsaren. Hur länge svaret cachas styr du per anrop, och det är ett eget ämne: läs guiden om caching i Next.js när grunderna sitter.
Dynamiska rutter
Ett mappnamn i hakparenteser blir en parameter. I app/produkter/[id]/page.js får sidan params som en promise:
import { notFound } from "next/navigation";
export async function generateMetadata({ params }) {
const { id } = await params;
const produkt = await hamtaProdukt(id);
return { title: produkt ? produkt.namn : "Produkten finns inte" };
}
export default async function ProduktPage({ params }) {
const { id } = await params;
const produkt = await hamtaProdukt(id);
if (!produkt) notFound();
return <h1>{produkt.namn}</h1>;
}notFound() avbryter renderingen och visar närmaste not-found.js. Vill du bygga sidorna i förväg, till exempel för en statisk export, exporterar du generateStaticParams som returnerar alla värden som id kan ha. Då vet Next.js vilka sidor som ska genereras vid bygget.
Navigation
Länka med Link från next/link i stället för en vanlig <a>. Then hämtar Next.js nästa sida i bakgrunden när länken syns på skärmen, och bytet sker utan att hela sidan laddas om.
import Link from "next/link";
<Link href={`/produkter/${produkt.id}`}>{produkt.namn}</Link>;Behöver du navigera från kod, till exempel efter att ett formulär skickats, använder du useRouter från next/navigation i en klientkomponent. Observera att importen är next/navigation, inte next/router som i Pages Router.
Laddningstillstånd
Skapa en loading.js i samma mapp som sidan. Next.js visar den automatiskt med React Suspense medan sidan väntar på data.
export default function Loading() {
return <div className="skeleton">Laddar...</div>;
}Laddningsgränsen läggs automatiskt runt page.js. Navigationen sker direkt och skelettvyn visas tills servern svarat. Vill du ha finare kontroll, så att en långsam del av sidan inte håller tillbaka resten, lägger du egna <Suspense>-gränser runt enskilda komponenter.
Felhantering
error.js fungerar som en React Error Boundary för rutten. Den måste vara en klientkomponent och tar emot ett error-objekt och en reset-funktion som försöker rendera sidan på nytt.
"use client";
export default function Error({ error, reset }) {
return (
<div>
<p>Något gick fel: {error.message}</p>
<button type="button" onClick={reset}>
Försök igen
</button>
</div>
);
}Fel i rotlayouten fångas inte av error.js, eftersom layouten ligger utanför gränsen. För det finns global-error.js, som då också måste rendera sina egna <html>- och <body>-taggar.
Nästa steg
Nu kan du strukturera ett projekt, hämta data och hantera laddning och fel. Nästa steg är Server Actions, som låter dig köra kod på servern direkt från ett formulär utan att skriva en API-rutt. Guiden Server Actions i praktiken tar vid här. Vill du först förstå var sidan ska köras finns guiden om att driftsätta Next.js.
