Herhalingsoefening I

Sebastiaan HenauOngeveer 6 minuten

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

Merk op dat styling gebruikt wordt als oefening en niet met het doel een productie-klaar resultaat neer te zetten. De styling van de oefening blijft heel beperkt.

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.

Oefening 0: Voorbereiding

Maak een nieuw project aan, verwijder alle bestanden binnen de src map en maak een lege main.tsx aan. Voeg de startbestandenopen in new window vervolgens toe aan het nieuwe project.

Tijdens deze oefeningen maak je opnieuw gebruik van Font Awesomeopen in new window. Ga voor installatie-instructies en voorbeelden kijken in de documentatieopen in new window of in de oefeningen van les 1

Naast Font Awesome gebruiken we in deze oefeningen ook onderstaande bibliotheek. Installeer deze.

pnpm add @faker-js/faker

Het UI van de zoekpagina is als volgt opgebouwd, de werking van de verschillende componenten wordt hieronder uitgelegd.

Figuur 1: App Structuur

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.

Figuur 2: FilterItem

De component bevat geen hardcoded data. Enkel de structuur wordt in deze 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.

Figuur 3: Filter

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 waaraan via styled-components volgende CSS-regel toegekend wordt.

margin-bottom: 1em;

Naast het weergeven van de opties moet de component opengeklapt kunnen worden (standaard open). Hiervoor gebruik je de state van de component Filter. Het pijltje naar beneden wordt door Font Awesome gedefinieerd in het object faCaretDown. Omring de naam van de categorie en het Font Awesome icoontje in een *<button> die via styled-components onderstaande CSS krijgt.

background: unset;
border: unset;

Een dichtgeklapte filter gebruikt het faCaretUp icoon en ziet er als volgt uit.

Figuur 4: Dichtgeklapte Filter

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:

Figuur 5: FilterBar

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.

Hint

Je kan verschillende interfaces samenvoegen tot een nieuwe interface die de properties van alle samengevoegde interfaces krijgt. Onderstaande component verwacht dus de properties uit de interfaces ExampleOne en ExampleTwo. Dit kan rechtstreeks, of door een extra interface te gebruiken.

import {FC} from 'react'

interface ExampleOne {
    propertyOne: string
}

interface ExampleTwo {
    propertyTwo: string
}

const Component: FC<ExampleOne & ExampleTwo> = ({propertyOne, propertyTwo}) => {
    return (
        <>
        </>
    )
}










 





Stappenplan voor het selecteren van een filter

Om een checkbox aan te vinken moet je volgende stappen doorlopen:

  1. Maak een nieuwe functie aan in de FilterBar component.
  2. Laat de nieuwe functie de toggleOptionSelected methode van de api oproepen.
  3. Laat de nieuwe functie ook de state bijwerken (getCategories oproepen).
  4. Geef de nieuwe functie door aan elke Filter component via een property.
  5. 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).
  6. Gebruik de in punt 5 aangemaakte functie in het onChange event van de FilterItem component.

Oefening 2: Styling

Installeer Bootstrap en react-bootstrap, zorg er vervolgens voor dat de juiste CSS geïmporteerd wordt.

SearchPage Page

Schrijf een component SearchPage, deze component deelt het scherm op in 2 kolommen, de eerste is 3 breed en bevat de filters, de tweede is 9 breed en bevat momenteel nog niets. Je mag ervan uitgaan dat deze layout voor elk breakpoint hetzelfde is. Gebruik tenslotte de Bootstrap klasse mt-5 om marge boven de SearchPage toe te voegen.

Filter Styling

Pas de tekst "Aanbevolen" aan naar de kleur "success", ga in de docsopen in new window op zoek naar de juiste klasse als je deze niet kent.

Figuur 6: Styling voor de filters

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.

Elke Computer component is omvat in een kolom die 4 groot is (op elk breakpoint). De Computer component is gebouwd met de Cardopen in new window component, deze krijgt een marge via de class 'me-4' De component gebruikt dezelfde afbeelding voor elke computer, het Font Awesome icoon faLaptop. Om het icoon de juiste afmetingen te geven kan je het in een div plaatsen waaraan onderstaande CSS gekoppeld is.

{
    font-size: 6rem;
    text-align: center;
}

Hieronder zie je twee rijen van computers staan. De namen van de verschillende properties zijn te vinden in de models.

Figuur 7: ComputerItem

Gebruikt de component ComputerList om onderstaand scherm na te bouwen.

Figuur 8: ComputerList

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.

Figuur 9: Filteren

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
Figuur 10: NavBar

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 pagina 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.

Figuur 11: Under Construction

Oefening 6: Scroll wrapper

Schrijf een component die rond één of meerdere componenten gezet kan worden om deze component(en) in hoogte te beperken tot een bepaald procent van de viewport height, of tot 100dvh als er geen specifieke waarde voor de property meegegeven is. Horizontaal scrollen is niet mogelijk, enkel verticaal scrollen is toegestaan. Gebruik compositie om deze component te implementeren.

Gebruik onderstaande CSS-code om de ScrollWrapper component via styled-components te implementeren. Ga kijken in de documentatieopen in new window en geeft de property die de maximale hoogte bepaald door aan de styled-component. Informatie over hoe je TypeScript kan gebruiken in combinatie met styled-components is ook terug te vinden in de documentatieopen in new window.

overflow-x: hidden;
overflow-y: scroll;
height: 100dvh;

Onderstaande video demonstreert de werking van deze component, ter illustratie is de hoogte van de FilterBar ingesteld op 85dvh en de ComputerList op 40dvh. Verwijder na het testen de ScrollWrapper rond de ComputerList.

Figuur 12: ScrollWrapper

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 Paginationopen in new window component van react-bootstrap en is omringd in volgende container.

const FlexContainer = styled.div`
  display: flex;
  flex-direction: column;
`

Deze container is opgedeeld in twee delen, het eerste deel wordt omringd met de DataContainer component die hieronder te vinden is en bevat de ScrollWrapper geplaatst. Het is opnieuw mogelijk om de hoogte door te geven, via de PaginationWrapper naar de ScrollWrapper. In onderstaande screenshots/video's is een hoogte van 75vh gebruikt. Binnen de ScrollWrapper wordt dan uiteindelijk de gepagineerde inhoud geplaatst.

const DataContainer = styled.div`
  flex-grow: 1;
  flex-direction: row;
  width: 100%;
  justify-content: center;
  .row {
    justify-content: center;
  }
`

const PaginationContainer = styled.div`
  display: flex;
  justify-content: center;
  margin-top: 1em;
`

Het tweede deel is de PaginationContainer die de navigatieknoppen bevat en waarvoor volgende richtlijnen gelden:

  • 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.

Gebruik onderstaande component om een navigatieknop te bouwen.

const StyledPageItem: typeof Pagination.Item = styled(Pagination.Item)`
  width: 2.5em;
  text-align: center;
`

In onderstaande video is een pagina grootte van 6 items gebruikt.

Figuur 13: Pagination

Oefening 8: Computer detail

Maak een detailpagina aan voor een laptop. Deze pagina is gebouwd met behulp van een Bootstrap Card en gebruikt het Bootstrap grid om twee aparte lijsten naast elkaar weer te geven. De marge tussen twee kolommen kan je weghalen door middel van de g-0 CSS-klasse toe te voegen aan de omringende rij.

Figuur 14: Detail pagina
Laatst geüpdate:
Bijdragers: Sebastiaan Henau