Ga naar de hoofdinhoud

1. Routing, Actions & Components

08-09-2023Ongeveer 10 minutenOngeveer 1481 woorden

1. Routing, Actions & Components

Tijdens deze oefeningenreeks oefen je op

  • Het aanmaken van een project
  • Het schrijven van componenten
  • Routing in Next.js
  • Server actions en form actions
  • Query en route parameters
  • Logging

Voorbereiding: Nieuw project & basisstructuur

Maak op basis van de instructies in de theorie een nieuw project aan. Installeer ook shadcn/ui en voeg daarna onderstaande startbestanden toe aan je project:

Startbestanden

Installeer Faker (een tool om test data te genereren) en de server-only library (die volgende theorieles besproken wordt) vervolgens met onderstaande commando's.

Root layout

Maak een root layout aan die gebruikt zal worden op alle pagina's (maak de standaard aangemaakte file leeg of verwijder deze en begin met een nieuwe). Hierin zet je:

  • Een titel voor je applicatie ("Oefening 1")
  • Metadata voor je applicatie:
    • De titel
    • Een omschrijving
    • Je eigen naam als auteur
  • Een titelbalk: dit is een h1 element met de titel van je applicatie als inhoud. De css klasse is text-2xl.

Gebruik de .css die gegenereerd is door Tailwind en breid deze uit met onderstaande css en zorg er tenslotte voor dat dit bestand in de volledige applicatie gebruikt wordt.

/* Standaard gegenereerde code */
h1 {
    background-color: black;
    color: white;
    padding-top: 0.5em;
    padding-bottom: 0.5em;
}

.text-white {
    --tw-text-opacity: 1;
    color: rgb(255 255 255 / var(--tw-text-opacity, 1)) /* #ffffff */;
}

.bg-black {
    --tw-bg-opacity: 1;
    background-color: rgb(0 0 0 / var(--tw-bg-opacity, 1)) /* #000000 */;
}

.bg-white {
    --tw-bg-opacity: 1;
    background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1)) /* #ffffff */;
}

.text-black {
    --tw-text-opacity: 1;
    color: rgb(0 0 0 / var(--tw-text-opacity, 1)) /* #000000 */;
}

Maak een page.tsx voor je homepage (maak de standaard aangemaakte file leeg of verwijder en begin met een nieuwe).

Deze toont voorlopig enkel de tekst "Dit is de homepage" in een standaard <p> tag.

Test of je app runt. Je zou volgend resultaat moeten zien:

Opzet
Figuur 1: Opzet

Routing

Maak 2 nieuwe pagina's aan: Boeken en Series. Voorlopig zet je op deze pagina's enkel een <p> tag die omschrijft over welke pagina het gaat. Maak op de homepage 2 links aan die de pagina's openen. Doe dat met de Link component. Gebruik Routing zoals uitgelegd in het lesvoorbeeld. Je mag deze links een mooie layout geven als je wil, maar focus je even op de werking.

Homepage start
Figuur 2: Homepage start

Maak een routing group aan voor de subpages. Hierin zet je de Series en Boeken pagina's. Gebruik die routing group om een aparte layout te voorzien. Deze layout bevat een knop 'Terug naar home' die teruggaat naar de home page.

Subpages start
Figuur 3: Subpages start

Server component

Kijk naar de bestanden in de dal map. Deze bevatten al enkele methodes om data op te halen en te bewerken. De methodes voeren ook telkens een vertraging uit, om te simuleren dat de request even op zich laat wachten.

Maak een component BookList aan en een component BookListItem. Deze zullen de boeken tonen op de 'Books' pagina. Houd de layout simpel en toon voorlopig enkel de naam van het boek en een knop om het boek te verwijderen (die nog niets moet doen). Je geeft het volledige IBook object door aan de BookListItem component. Zet die 2 components in een submap die genegeerd wordt door routing.

Boeken pagina
Figuur 4: Boeken pagina

Client component

We willen op de boeken pagina een filter op titel toevoegen. Hiervoor zullen we useState gebruiken (je kan hiervoor ook de submit van een form gebruiken zoals in de theorie, maar voor deze oefening gebruiken we useState). We simuleren dat de connectie naar de server lang duurt. Aangezien we niet veel boeken hebben, en we snel willen kunnen filteren, gaan we de server 1 keer alle boeken laten ophalen en de client laten filteren.

Zorg ervoor dat de boeken al worden opgehaald in de page van de boeken, geef die boeken door aan de BookList component, en maak van de BookList een client component.

Maak een tekstveld bij aan om te kunnen filteren op de naam van de boeken. Gebruik useState daarbij. Filter direct wanneer de gebruiker typt. Weet je niet waar beginnen voor die filter? Check dan eerst eens terug in de cursus van Frontend bij hoofdstuk 2.

Boeken filters
Figuur 5: Boeken filters

Server actions + revalidate

Maak een nieuwe server action die een boek uit de lijst verwijdert. Aangezien de action niet aan een formulier gekoppeld is, maar aan een knop, gebruik je een server action en eventueel de useTransition hook. Zorg ervoor dat de pagina opnieuw valideert.

Let op: omdat loading/suspense nog niet toegepast zijn lijkt de app even niets te doen. Even geduld 😃.

Na verwijderen van 'The Fellowship of the Ring' en 'The Return of the King'
Figuur 6: Na verwijderen van 'The Fellowship of the Ring' en 'The Return of the King'

Loading

Maak een loading page voor de boeken. Je mag deze simpel houden en gewoon een tekst tonen: 'Loading...'. Je mag hier ook iets mooier van maken, maar verlies er niet te veel tijd mee.

Loading page boeken
Figuur 7: Loading page boeken

Form action + redirect

Maak een nieuwe pagina aan waarmee een nieuw boek toegevoegd kan worden. Voorzie een nieuwe knop op de boeken pagina om naar het create formulier te gaan.

Nieuw boek knop
Figuur 8: Nieuw boek knop

Gebruik de voorziene functie in de DAL laag om een form action te schrijven die een nieuw boek toevoegt en de gebruiker daarna terug redirect naar de boeken pagina.

Figuur 9: Loading page boeken

Route parameters + redirect

Maak een nieuwe page aan om de details van een boek te bekijken die bezocht kan worden door op een boek te klikken. Gebruik hiervoor een route parameter. Toon de titel van het boek en de link naar Amazon. Toon daaronder een lijst van alle boeken uit dezelfde serie. Voor deze lijst gebruik je BookListItem opnieuw. Programmeer de link naar de detailpagina ook in BookListItem en je zal kunnen 'doorklikken' naar andere boeken uit de serie.

Detailpagina boek
Figuur 10: Detailpagina boek

Wanneer het boek niet gevonden kan worden, redirect je naar de overzichtspagina van de boeken. Dit kan je testen door naar een bestaand boek te gaan en in de URL de id aan te passen.

Suspense

In de detailpagina worden nu 2 dingen opgehaald: het boek en de andere boeken uit de serie. Zorg er met Suspense voor dat de info van het boek al laadt, en een component met de tekst 'Loading...' getoond wordt terwijl de boeken uit de serie opgehaald worden.

Detailpagina boek loading
Figuur 11: Detailpagina boek loading

Query parameters

In de utils map van de startbestanden kan je een methode vinden die een css klasse terug geeft op basis van een thema. Bouw in de root page een dropdownlist waar de thema's 'dark' en 'light' aangeboden worden. Zorg er via query parameters voor dat je het thema kan aanpassen. Gebruik de css klasse die je terugkrijgt op minstens 1 element in je page om te testen.

Thema
Figuur 12: Thema

Error boundary

Bouw een error boundary rond alle 'subpages' (boeken, series en eventuele detailpagina's). Toon zowel de omschrijving van de error als een link naar de homepage. De error wordt meegegeven als een property aan de error boundary, de naam van deze property is error en het type is NextError.

Error boundary
Figuur 13: Error boundary

Logging

Installeer en configureer pino en pino-pretty.

Zorg voor error logging analoog aan de theorie les, en zorg ervoor dat het request id getoond wordt op de error pagina.

Voeg op enkele plaatsen in de server functies logging toe. Log in je dal laag de id van het aangemaakt boek in de create functie en in de get hoeveel boeken er opgehaald worden.

De useCookie hook kan je hergebruiken uit de bestanden van de theorie les.

Optionele uitbreiding: doe je log naar een bestand + log hoeveel milliseconden de actie naar de server geduurd heeft.

Optioneel Herhaling

Maak ook voor de series pagina een lijst waarin je kan filteren. Gebruik voor het filteren dit keer een form met een GET request en query parameters.

Schrijf ook een action waarmee een series verwijderd kan worden.

Series pagina
Figuur 14: Series pagina

Als de gebruiker op de titel van een serie klikt, wordt de detailpagina getoond waar een lijst getoond wordt van de boeken in de serie.

Series detailpagina
Figuur 15: Series detailpagina