Ga naar hoofdinhoud

Routing

Tot nu toe bestonden onze applicaties uit één enkele pagina. Dit is niet erg handig als je een volledige website wil maken. Daarom is er een manier nodig om meerdere pagina's te maken. Dit kan met behulp van een router. Een router is een stukje code dat bepaalt welke pagina getoond moet worden op basis van de URL.

Next.js biedt twee verschillende routers aan: de Pages Router en de App Router. In deze cursus gaan we enkel gebruik maken van de Pages Router. Deze is eenvoudiger in gebruik en is voldoende voor de meeste applicaties. Ook wordt de App Router nog niet aanbevolen door de officiele React documentatie.

File-system based router

Next.js maakt gebruik van een zogenaamde "file-system based" router. Dit betekend dat we geen extra code moeten schrijven om de router te configureren. We moeten enkel een aantal bestanden en directories aanmaken en de router zal automatisch de juiste pagina tonen op basis van het pad.

Als je een nieuw tsx bestand aanmaakt in de pages directory zal dit automatisch een nieuwe pagina worden. Als je bijvoorbeeld een bestand pages/about.tsx aanmaakt, dan zal dit bestand getoond worden als je naar http://localhost:3000/about surft.

const About = () => {
return <div>About</div>;
}

export default About;

Index route

Je kan ook gebruik maken van de index.tsx bestanden om de index route te configureren. Als je bijvoorbeeld de volgende bestanden aanmaakt dan krijg je ook de bijbehorende routes:

pages/index.tsx → /
pages/blog/index.tsx → /blog

Je kan zelfs geneste routes maken:

pages/blog/first-post.tsx → /blog/first-post
pages/dashboard/settings/username.tsx → /dashboard/settings/username

Dynamische routes

Wil je gebruik maken van dynamische routes. Bijvoorbeeld als je een blog wil maken waarbij de URL van de blogpost de titel of id van de blogpost bevat. Dan kan je gebruik maken van dynamische routes. Je kan dit doen door een bestand aan te maken met de naam van de route tussen vierkante haken.

pages/posts/[id].jsx/posts/1, /posts/2, ...
pages/posts/[id]/index.jsx/posts/1, /posts/2, ...

Wil je dan in je component gebruik maken van de id, dan kan je dit doen door gebruik te maken van de useRouter hook. Deze hook geeft je toegang tot de router en de parameters die je hebt meegegeven in de URL.

import { useRouter } from "next/router";

const Posts = () => {
const router = useRouter()
return <p>Post: {router.query.id}</p>
}

export default Posts;

Linking and Navigating

Om te navigeren tussen de verschillende pagina's kan je gebruik maken van de Link component. Deze component zorgt ervoor dat de pagina niet opnieuw moet laden als je naar een andere pagina navigeert. Dit zorgt voor een betere gebruikerservaring.

import Link from "next/link"

const Home = () => {
return (
<div>
<Link href="/about">
<a>About</a>
</Link>
</div>
)
}

export default Home;

Je kan bij de Link component ook gebruik maken van dynamische routes. Hier gebruik je meestal string interpolation om de juiste URL te genereren.

import Link from "next/link"

const Home = () => {
let pages : string[] = [1,2,3,4,5];
return (
<div>
{pages.map((page) => (
<Link href={`/posts/${page}`} key={page}>
{page}
</Link>
))}
</div>
)
}

export default Home;

of je kan ook gebruik maken van een object om de URL te genereren.

import Link from "next/link"

const Home = () => {
let pages : string[] = [1,2,3,4,5];
return (
<div>
{pages.map((page) => (
<Link href={{ pathname: '/posts/[id]', query: { id: page } }} key={page}>
{page}
</Link>
))}
</div>
)
}

export default Home;

via de useRouter hook kan je ook navigeren naar een andere pagina zonder gebruik te maken van de Link component. Dit is handig als je bijvoorbeeld wil navigeren op basis van een event.

import { useRouter } from "next/router"

const Home = () => {
const router = useRouter()
return (
<div>
<button onClick={() => router.push('/about')}>About</button>
</div>
)
}

export default Home;

Interessant om te weten: Next.js zal aan de hand van de links bepaalde pagina's gaan prefetchen. Dit wil zeggen dat de pagina al wordt opgehaald voordat de gebruiker erop klikt. Dit zorgt ervoor dat de pagina sneller zal laden als de gebruiker erop klikt. Dit is standaard ingeschakeld, maar je kan dit uitschakelen door de prefetch property op false te zetten.

Custom App

Als je wil gebruik maken van een Layout component die op elke pagina getoond moet worden, dan kan je gebruik maken van de Custom App functionaliteit van Next.js. Dit is een component dat je kan aanmaken in pages/_app.tsx. Dit component wordt dan gebruikt als de basis van je applicatie. Je kan hier bijvoorbeeld de Layout component toevoegen.

import type { AppProps } from 'next/app';
import Layout from '../components/Layout';

const MyApp = ({ Component, pageProps }: AppProps) => {
return (
<Layout>
<Component {...pageProps} />
<Layout>
);
}

export default MyApp;

met als bijbehorende Layout component:

const Layout = ({ children } : {children: ReactElement}) => {
return (
<div>
<h1>Header</h1>
{children}
<h1>Footer</h1>
</div>
);
}

export default Layout;

Deze code zorgt ervoor dat alle pagina's worden omgeven door de Layout component.

Custom Document

Als je wil gebruik maken van een custom Document dan kan je dit doen door een bestand pages/_document.tsx aan te maken. Dit bestand wordt gebruikt om de HTML te genereren. Wil je bijvoorbeeld een custom head toevoegen aan je applicatie, dan kan je dit doen door het volgende bestand aan te maken. Je kan hier ook externe CSS of javascript bestanden toevoegen (bv voor fontawesome).

import Document, { Html, Head, Main, NextScript } from 'next/document'

class MyDocument extends Document {
render() {
return (
<Html lang="en">
<Head>
<meta name="description" content="My custom description" />
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}

export default MyDocument;

Je ziet hier dat we gebruik maken van het Head component. Deze component zorgt ervoor dat de inhoud van de head tag wordt aangepast. Je kan hier bijvoorbeeld de title van de pagina aanpassen of een meta tag toevoegen. Je kan dit component ook gebruiken op aparte pagina's om een custom head toe te voegen voor die pagina.

import Head from 'next/head'

const About = () => {
return (
<div>
<Head>
<title>About</title>
</Head>
<h1>About</h1>
</div>
)
}

export default About;

Custom error pages

Normaal gezien moet je geen gebruik maken van custom error pages. Next.js zal automatisch de juiste error pagina tonen als er iets mis gaat. Wil je toch gebruik maken van een custom error pagina, dan volstaat het een bestand aan te maken met als naam de status code van de error. Bijvoorbeeld pages/404.tsx voor een 404 error.

const Custom404 = () => {
return <h1>404 - Page Not Found</h1>
}

export default Custom404;

router.isReady

Als je gebruik maakt van de useRouter hook en je wil de router gebruiken in een useEffect hook, dan kan het zijn dat de router nog niet klaar is. Dit kan je oplossen door gebruik te maken van de router.isReady property. Deze property geeft aan of de router klaar is of niet.

import { useRouter } from "next/router"

const Home = () => {
const router = useRouter()
useEffect(() => {
if (router.isReady) {
// Do something with the router
}
}, [router.isReady])
return <div>Home</div>
}

Bijvoorbeeld als je een API call wil doen die afhankelijk is van een query parameter kan je dit oplossen door te wachten tot de router klaar is.

import { useRouter } from "next/router"

const Posts = () => {
const router = useRouter()
useEffect(() => {
if (router.isReady) {
fetch(`https://api.example.com/posts/${router.query.id}`)
.then(response => response.json())
.then(data => console.log(data))
}
}, [router.isReady, router.query.id])
return <div>Posts</div>
}