Les 2: State

Sebastiaan HenauOngeveer 6 minuten

Les 2: State

Deze oefeningenreeks bouwt verder op de oplossingen van de vorige oefeningenreeks. Je kan verder werken van je eigen oplossingen of gebruik maken van de op Canvas gepubliceerde oplossingen. Maak net zoals in de vorige les voor elke oefening een nieuwe component aan. Voor deze oefeningenreeks zijn startbestanden voorzien, clone het repositoryopen in new window en plaats de src map in je oplossingen van les 1 (of in de aangeboden oplossingen). Tijdens deze oefeningenreeks oefen je op:

  • De concepten van les 1
  • State
  • de useState hook
  • Lifting state & prop-drilling
  • Composition & inheritance
  • Context

Oefening 1: Key toevoegen

Je hebt vorige oefeningenreeks in de eerste, tweede en vierde oefening gebruik gemaakt van array. Je hebt daar toen geen key aan meegegeven, als je in de console kijkt zal je hier dan ook waarschuwingen over zien.

De componenten die in de arrays zitten gaan nooit van structuur veranderen, elk rij in de maaltafel zal steeds dezelfde waarde bevatten (xâ‹…y=zx \cdot y = z), gebruik de getallen in de maaltafel (zz) als key. De rater heeft steeds exact evenveel sterren, deze sterren staan steeds in dezelfde volgorde, hier kan je dus een oplopende index gebruiken als key. Voor de vierde opgave kan je ook een eenvoudige key gebruiken, het getal dat in het vakje weergegeven wordt en het rijnummer.

Oefening 2: Calculator

Gebruik het startbestand exerciseSix.tsx en zorg er voor dat je bij het starten van het project het onderstaande te zien krijgt (de andere oefeningen zijn weggelaten in het screenshot).

Figuur 1: Calculator - Enkel het scherm is zichtbaar

Bouw de rekenmachine verder uit, hou er rekening mee dat elke druk op de knop zichtbaar moet zijn op het scherm. Je zal dus gebruik moeten maken van state.

Figuur 2: Calculator - Label

In het startbestand vind je een array die alle knoppen bevat die in de rekenmachine moeten verschijnen, in de juiste volgorde. Gebruik deze array om de 12 knoppen te renderen. Zorg er vervolgens voor dat de knoppen werken en de aangedrukte knoppen ook zichtbaar worden op het label. De "C" knop maakt het volledige scherm leeg en de "Del" knop verwijdert het laatst ingedrukte cijfer.

Figuur 3: Calculator

Oefening 3: BMI Calculator

Gebruik de startbestanden exerciseSeven.tsx en range.css om onderstaand resultaat te bekomen (de andere oefeningen zijn weggelaten in het screenshot).

Figuur 4: BMI Calculator - Start

Bouw een component Slider, die vier properties heeft, value, min, max en changeHandler. Value geeft de huidige waarde van de slider, min de minimale en max de maximale waarde. De laatste property changeHandler bevat een functie die gebruikt wordt om de waarde van de slider aan te passen (in de bovenliggende component). Voor deze property kan je het type ChangeEventHandler<HTMLInputElement> gebruiken. De Slider is een invoerelement van het type range als je hiermee niet bekend bent kan je op MDNopen in new window meer info vinden. Gebruik deze component en de BmiLabel component die in de startbestanden aanwezig is om het volgende te realiseren. Kies zelf realistische minimum en maximum waarden.

Figuur 5: BMI Calculator

Zorg er tenslotte voor dat de sliders automatisch updaten. Telkens de hoogte of het gewicht aangepast wordt moet ook de BMI aangepast worden. De formule om de BMI te berekenen vind je ook in het startbestand.

Figuur 6: BMI Calculator

Oefening 4: Comments en lifting state

Breid oefening 5 van vorige les uit zodat de inhoud van de commentaar (CommentContent) maar voor een stuk zichtbaar is. Voeg daarachter een klikbare tekst 'read more' toe die de volledige tekst toont wanneer erop geklikt wordt. Als de tekst toegeklapt is, worden slechts de 30 eerste karakters getoond.

Zorg ervoor dat de tekst slechts voor één CommentCard tegelijkertijd uitgeklapt kan zijn. Je hoeft hiervoor geen composition te gebruiken.

Je kan gebruik maken van volgende opmaak voor de 'read more'/'show less' tekst:

{
    font-size: 110%;
    text-decoration: underline;
    color: #6b6b6f;
    cursor: pointer;
    margin: 0;
}
Figuur 7: Show less/more in de CommentCard

Bouw een carousel component via composition, je hoeft in deze opgave nog geen gebruik te maken van context. We beperken ons in deze opgave tot een image carousel, kinderen die meer dan een afbeelding bevatten worden momenteel niet correct gebruikt omdat de CSS daarvoor niet voorzien is.

Voor deze oefening krijg je vier startbestanden, geen van deze bestanden moet aangepast worden. De component ControlButton wordt gebruikt om de pijlen om naar links of rechts te navigeren aan te bouwen. De component heeft één property prev waarmee de positionering bepaald wordt, als prev op true staat wordt de knop links gepositioneerd, anders rechts. Deze component is een gewone <button>, je kan hier dus rechtstreeks een onClick handler aan koppelen. Tenslotte kan je de HTML-entiteiten &lt; en &gt; als vorige en volgende teken.

De component CarouselContainer bevat in de eerste versie van deze opgave geen speciale properties en moet gewoon rond de rest van de componenten geplaatst worden.

De andere startbestanden kunnen gebruikt worden om willekeurige afbeeldingen te generen om in de carousel te plaatsen, dit kan met de getRandomImage functie die in images.ts te vinden is.

Gebruik deze componenten om onderstaande structuur te bouwen, de blauw ingekleurde componenten worden als kind doorgegeven, via de children property. Je moet minstens 3 afbeeldingen gebruiken in je carousel.

Als de gebruiker op de vorige of volgende knop drukt, moet respectievelijk het vorige of volgende kind van de carousel getoond worden. Natuurlijk moet je hiervoor wel een bepaald kind kunnen selecteren uit de children array, dit kan via onderstaande code.

File not found

Tenslotte moet het mogelijk zijn om circulair te blijven navigeren, als de gebruiker de laatste slide aan het bekijken is en op de volgende knop drukt, moet de eerste slide terug getoond worden. Als de gebruiker de eerste slide aan het bekijken is en op de vorige knop drukt, moet de laatste slide getoond worden. Onderstaande video toont het beoogde resultaat.

Hint

Als de afbeeldingen pas geladen worden op het moment dat deze zichtbaar moeten zijn in de carousel, zal de pagina verspringen omdat de afbeelding even geen afmetingen heeft (nog niet geladen). Je scherm zal naar boven verspringen omdat de scroll-zone kleiner is. Als de afbeelding geladen is, wordt de scroll-zone terug groter. Dit is niet ideaal, je kan onderstaand tsx fragment gebruiken om de afbeeldingen al in het geheugen te laden zodat de overgang aangenamer is voor de gebruiker.

const preloadImages = (
    <div style={{'display': 'none'}}>
        {children}
    </div>
)
Figuur 8: Carousel versie 1

Optionele uitbreiding: Animaties

Deze opgave is relatief complex en moet niet verplicht gemaakt worden. Dat gezegd is het probleem hier meer de complexe logica en minder moeilijkheden specifiek te wijten aan React. Iedereen wordt aangemoedigd om de oefeningen te proberen.

De CarouselContainer component bevat de mogelijkheid om het wisselen tussen afbeeldingen te animeren. Er zijn twee CSS-klassen beschikbaar slideOutRight en slideOutLeft. Er zijn twee mogelijke situaties, in onderstaande voorbeelden is de vetgedrukte component diegene die gerenderd wordt.

  1. De gebruiker navigeert naar de volgende slide, in dit geval zien de gerenderde slides er als volgt uit: vorigeSlide volgendeSlide → slideOutLeft animatie → vorigeSlide volgendeSlide
  2. De gebruiker navigeert naar de vorige slide, in dit geval zien de gerenderde slides er als volgt uit: volgendeSlide vorigeSlide → slideOutRight animatie → volgendeSlide vorigeSlide

De animaties kunnen geactiveerd worden door de slideOutRight en slideOutLeft klassen toe te voegen aan de CarouselContainer component. Het resultaat ziet er ongeveer als volgt uit.

Figuur 9: Carousel versie 2, met animaties

Oefening 6: Tabs

Bouw een tabs component via composition. Gebruik context om bij te houden welk tabblad actief is.

In de startbestanden zijn enkele componenten te vinden die je kan gebruiken voor de styling, de TabButton en TabPanelContentContainer componenten hebben een property isActive die gebruikt kan worden om de styling aan te passen naargelang de knop of het paneel al dan niet actief/zichtbaar zijn. Gebruik onderstaande structuur om de oefening uit te werken. De blauw ingekleurde componenten moeten opnieuw doorgegeven worden als kind van de bovenliggende component (via de children property). Hieronder wordt de structuur getoond voor één tabblad, je zal dus meer Tab en TabPanel componenten moeten gebruiken dan in onderstaand diagram.

Figuur 10: Tabs component met 4 tabbladen

Oefening 7: Exercise uitbreiden

Breid de Exercise component uit zodat deze individueel open of dichtgeklapt kunnen worden, maar ook allemaal tegelijk op open of dicht gezet kunnen worden. Je mag voor deze opgave geen composition of context gebruiken. Alles (moet dus van parent naar child doorgegeven worden via properties.

Begin met knop toe te voegen aan de Exercise component, zoals in onderstaand screenshot. Je kan de hiervoor de ChevronBtn component gebruiken die je in de startbestanden terugvindt. De knop moet nog niet doen.

Afhankelijk van de open/gesloten state, wordt de inhoud van de knop anders opgevuld.

import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import {faChevronDown, faChevronUp} from '@fortawesome/free-solid-svg-icons'

const openBtn = <FontAwesomeIcon icon={faChevronUp}/>
const closedBtn = <FontAwesomeIcon icon={faChevronDown}/>
Figuur 11: Knop in gesloten toestand
Figuur 12: Knop in open toestand

Voeg vervolgens bovenaan de pagina volgende twee knoppen toe, de eerst knop zal gebruikt worden om alle oefeningen dicht te klappen, de volgende om alle oefeningen open te klappen. Je kan hiervoor de OpenCloseBtn component gebruiken die je in de startbestanden vindt. De knoppen moeten nog niet werken.

Figuur 13: Knoppen om alles te openen/sluiten

Zorg er tenslotte voor dat alle knoppen die je hierboven toegevoegd hebt werken. Als je de pagina opent is alles standaard geopend. Hou rekening met volgende hints:

  • Denk voor je begint met het implementeren goed na over de locatie van de state.
  • Weet dat hooks zoals useState enkel in een component gebruikt kunnen worden.
  • Arrays kunnen in de state bewaard worden
    • Elk element in de array moet gekopieerd worden naar een nieuwe array bij het aanpassen van de state. Hiervoor kan je de spread operator gebruikt. const new = [...old]
Figuur 14: Knoppen om alles te openen/sluiten
Laatst geüpdate:
Bijdragers: Sebastiaan Henau