Herhalingsoefening I
Herhalingsoefening I
Tijdens deze oefensessie bouw je een (klein deel van) een webshop na in React. Tijdens deze les oefen je op alle geziene concepten:
- Componenten
- State
- Lifting state
- Prop drilling
- Routing
- Styling
- Het gebruik van third-party UI libraries
- Het raadplegen van documentatie om relevante informatie te vinden
We bouwen een webshop pagina met een aantal laptops waarvan de specificaties automatisch gegenereerd zijn. De website stelt de gebruiker in staat om de beschikbare laptops te filteren op basis van deze specificaties en om een detailpagina te bekijken.
Info
Deze oefening vertrekt van een bottom-up approach in de plaats van de top-down approach die de voorbije lessen gebruikt is. Op deze manier kunnen we alle leerstof vanaf de eerste les herhalen en toepassen.
Voorbereiding
Maak een nieuw project aan, verwijder alle bestanden binnen de src map en maak een lege main.tsx aan. Voeg de startbestanden vervolgens toe aan het nieuwe project.
Startbestanden
Tijdens deze oefeningen maak je opnieuw gebruik van shadcn/ui en Tailwind CSS.
Verder maken de startbestanden ook gebruik van Faker.js om willekeurige data te genereren.
Het UI van de zoekpagina is als volgt opgebouwd, de werking van de verschillende componenten wordt hieronder uitgelegd.

Oefening 1: Filters
Elke webshop heeft nood aan een manier om de beschikbare producten te filteren. We beginnen hiermee. Een filter bestaat uit een titel en een aantal opties. Voor de titel "Merk" zijn er bijvoorbeeld de opties "Acer", "Apple", ... De filter kan dichtgeklapt worden om de opties te verbergen. Dit dichtklappen programmeer je zelf, maak geen gebruikt van bibliotheken of componenten die dit voor jou doen.
We bouwen de component van onder naar boven uit en beginnen dus met de componenten zonder state en bouwen dan de stateful components die deze eerste componenten gebruiken.
Opties
Maak een nieuwe component FilterItem. Het onderstaande screenshot toont de opties voor de eerste categorie in de array die teruggegeven wordt door de getCategories functie. Elke optie is een FilterItem component. Zorg er verder ook voor dat de tekst "Aanbevolen" in de juiste kleur wordt weergegeven, maak hiervoor gebruik van Tailwind.

De component bevat geen hardcoded data. Enkel de structuur wordt in de component gedefinieerd, alle effectieve data wordt via properties doorgegeven. Bekijk de API-code en models om de juiste property-namen te vinden.
Filteren
Maak een nieuwe component Filter, deze component is opgebouwd uit verschillende FilterItems. Daarnaast toont de component ook de titel van de categorie.

Een Filter component heeft twee properties, name en options. De waarden van deze properties kunnen opnieuw opgehaald worden met behulp van de getCategories functie, dit keer geef je een volledige categorie door aan de Filter component. Verder wordt de component omringt in een <div> met de CSS-klasse mb-1.
Naast het weergeven van de opties moet de component opengeklapt kunnen worden (standaard open). Hiervoor gebruik je de state van de component Filter. Zoek in Lucide naar de juiste (caret) iconen om de filter open en dicht te klappen. Een dichtgeklapte filter ziet er als volgt uit.

Alle filters
Schrijf een nieuwe component FilterBar die alle filters onder elkaar toont. Daarnaast moet deze component in zijn state de categorieën en bijhorende opties bewaren.
Op basis van de state worden de verschillende Filter componenten gebouwd. Het resultaat:

Filters selecteren
Momenteel kunnen de filters nog niet geselecteerd worden. Dit is natuurlijk niet ideaal. Probeer eerst zelf te zorgen dat de opties binnen elke filter geselecteerd kunnen worden. Als dit niet lukt, kan je de hints hieronder bekijken.
Stappenplan voor het selecteren van een filter
Om een checkbox aan te vinken moet je volgende stappen doorlopen:
- Maak een nieuwe functie aan in de FilterBar component.
- Laat de nieuwe functie de toggleOptionSelected methode van de api oproepen.
- Laat de nieuwe functie ook de state bijwerken (getCategories oproepen).
- Geef de nieuwe functie door aan elke Filter component via een property.
- Geef tijdens het oproepen van elke FilterItem component een nieuwe lambda (arrow) functie door (via properties) aan het FilterItem. Deze lambda functie roept de functie uit punt 4 op met de correcte parameter (het id van de optie die weergegeven wordt door het FilterItem en de categorie waarin dit FilterItem zich bevindt).
- Gebruik de in punt 5 aangemaakte functie in het onClick event van de FilterItem component.
SearchPage Page
Schrijf een component SearchPage, deze component deelt het scherm op in 2 kolommen. De eerste kolom neemt 1/4 van de beschikbare ruimte in beslag en bevat de FilterBar component. De tweede kolom neemt 3/4 van de beschikbare ruimte in beslag en bevat momenteel nog niets.
Oefening 3: ComputerList
Bouw een component ComputerList, deze component maakt gebruik van een component Computer om een overzicht te tonen van elke computer die voldoet aan de geselecteerde filters.
De computers worden ingedeeld in een grid waar elke computer 1/3 van een rij in beslag neemt. De Computer component is gebouwd met de Card component en gebruikt hetzelfde laptop icoon voor elke computer. Om het icoon de juiste afmetingen te geven kan je het in een div plaatsen waaraan onderstaande CSS gekoppeld is.
Je resultaat moet er als volgt uitzien, de namen van de properties kan je vinden in de models.

Oefening 4: Filteren
Je merkte waarschijnlijk al op dat het filteren nog niet werkt. Dit komt omdat de geselecteerde filters bijgehouden worden in de component FilterBar. Je moet dit nog een niveau naar boven verhuizen. De geselecteerde filters moeten in de state van de SearchPage component bijgehouden worden. Zo kan, op het moment dat er een filter geselecteerd wordt, een re-render gebeuren van de FilterBar en ComputerList componenten.
Oefening 5: Routing
Voeg een navbar toe aan je applicatie. De navbar bevat de links:
- Laptops: /laptops
- Smartphones: /smartphones
- Keuken: /kitchen
- Wasmachines: /washing-machines
- About: /about

Installeer de nodige pakketten voor routing. Zorg er voor dat de links achter "Small Webshop" en "Laptops" allebei naar de SearchPage component verwijzen.
Voor alle andere pagina's is geen speciale inhoud voorzien. Bouw een catch-all route die alle niet gekende paden doorstuurt naar de UnderConstruction component. Deze component bevat onderstaande inhoud. Ook als je de root page van de site open ('/') moet je op de SearchPage component komen.

Oefening 6: Scroll wrapper
Gebruik de ScrollArea component om ervoor te zorgen dat de er individueel gescrolled kan worden door de FilterBar en ComputerList componenten.
Oefening 7: PaginationWrapper
Schrijf een component PaginationWrapper die rond een andere component gezet kan worden en gebruikt kan worden voor pagination. Het is niet mogelijke om deze component op een goede manier te bouwen met behulp van composition. Je zal dus (onder anderen) properties moeten doorgeven aan deze component die de actieve pagina aanduiden en properties om deze te wijzigen.
De PaginationWrapper is gebouwd met behulp van de Pagination component van shadcn/ui. Voor de knoppen van de pagination knoppen gelden volgende vereisten:
- De knop om naar de eerste pagina te gaan is altijd zichtbaar.
- De knop om naar de vorige pagina te gaan is altijd zichtbaar.
- Er worden steeds 5 knoppen getoond de active pagina is de middelste in deze lijst tenzij:
- Er minder dan 5 pagina's zijn.
- De active pagina 1 of 2 is en er meer dan 5 pagina's zijn.
- De active pagina is 0 of 1 positie verwijderd van de laatste pagina.
- De knop om naar de laatste pagina te gaan is altijd zichtbaar.
- De knop om naar de volgende pagina te gaan is altijd zichtbaar.
- Als er slechts 1 pagina beschikbaar is worden de knoppen verborgen.
In onderstaande video is een pagina grootte van 6 items gebruikt.
Oefening 8: Computer detail
Maak een detailpagina aan voor een laptop. Deze pagina is gebouwd met behulp van de Card component en de ListGroup component uit de oefeningen van les 3. Merk op dat je deze component nog moet aanpassen zodat de border niet meer zichtbaar is.
Tenslotte moet er een knop zijn om terug te keren naar de SearchPage, als je via de / route naar /laptops/:id navigeert moet de knop je terug naar de / route brengen. Als je echter via /laptops naar /laptops/:id navigeert moet de knop je terug naar de /laptops route brengen.
