Dierenasiel De Warme Poot
Download het starterproject en voer daarna npm install uit.
📂 Naam project:
lab-context-petshelter
🔗 Basisproject: de vereiste begincode is inbegrepen in het starterproject.
Dierenasiel De Warme Poot heeft een website waar honden, katten en konijnen een nieuwe thuis zoeken. De site is al volledig opgebouwd uit kleine componenten, maar twee dingen werken nog niet:
- de knop om naar het donkere thema te wisselen doet niets;
- de knop Ik wil adopteren doet ook niets.
Beide functies hebben gegevens nodig in componenten die heel diep in de boom zitten. In plaats van die gegevens via props door elk tussenliggend component door te geven (prop drilling), gebruik je in dit labo context.
De structuur van de applicatie
Bekijk eerst de componenten in src/components. De boom ziet er zo uit:
App
└── Layout
├── Header
│ ├── Logo
│ ├── Nav
│ │ └── NavLink
│ └── ThemeToggle
├── Main
│ ├── Intro
│ ├── Statistieken
│ │ └── StatKaart
│ └── DierenOverzicht
│ ├── SoortFilter
│ │ └── FilterKnop
│ └── DierenLijst
│ └── DierKaart
│ ├── DierAvatar
│ ├── DierInfo
│ │ ├── SoortBadge
│ │ └── StatusBadge
│ └── AdopteerKnop
└── Footer
De dieren zelf staan in src/app/dieren.ts. Daar vind je ook de types Dier en Soort.
Deel 1: ThemeContext
Elk element in de applicatie heeft naast zijn eigen klasse ook de klasse light, bijvoorbeeld:
<article className="dier-kaart light">
In App.css zie je dat de klassen light en dark de kleuren bepalen. Als je overal light vervangt door dark, krijg je dus het donkere thema. Die klasse staat nu nog hardgecodeerd in elk component.
-
Maak een bestand
src/context/ThemeContext.tsxaan. Definieer daarin een typeThemedat de waarde'light'of'dark'kan hebben. -
Maak met
createContexteenThemeContextaan met twee waarden:theme(van het typeTheme) entoggleTheme, een functie zonder parameters die het thema omwisselt. Geef een interface mee aancreateContexten voorzie een default value ('light'en een lege functie). -
Maak in hetzelfde bestand een component
ThemeProviderdat eenchildrenprop krijgt. Dit component houdt het thema bij metuseState, schrijft de functietoggleThemeen geeft beide door aanThemeContext.Provider. -
Zet de
ThemeProviderinApp.tsxrond deLayout. -
Pas elk component aan zodat het niet langer de vaste klasse
lightgebruikt, maar het thema uit de context haalt metuseContext:<article className={`dier-kaart ${theme}`}> -
Laat de
ThemeTogglewerken: bij een klik roept hijtoggleThemeaan. Toon in het licht thema het icoon 🌙 met het labelDonker, en in het donker thema het icoon ☀️ met het labelLicht.
Merk op dat je hiervoor geen enkele nieuwe prop hebt moeten toevoegen. ThemeToggle zit in de Header en SoortBadge zit vijf niveaus diep in Main, en toch lezen ze allebei dezelfde waarde.
Deel 2: DierenContext
Nu staat de lijst DIEREN als constante in Main en wordt ze via props doorgegeven aan Statistieken en DierenOverzicht. Omdat het een constante is, kan een dier nooit geadopteerd worden.
- Maak een bestand
src/context/DierenContext.tsxaan met eenDierenContext. De context bevat:dieren: de lijst met alle dieren (Dier[]);adopteer: een functie die eenid: numberkrijgt en het dier met dat id opgeplaatst: truezet.
- Maak een component
DierenProviderdat de dieren in een state bijhoudt (startwaardeDIEREN) en de functieadopteerimplementeert. Pas de state aan zonder de bestaande array te muteren. - Zet de
DierenProviderinApp.tsx. Zowel deThemeProviderals deDierenProvidermoeten rond deLayoutstaan. - Verwijder de
dieren-props vanStatistiekenenDierenOverzicht. Beide componenten halen de dieren nu zelf op uit deDierenContext.Mainhoeft niets meer te weten over de dieren. - De
AdopteerKnopkrijgt nu enkel nog hetidvan het dier mee (in plaats vangeplaatst). De knop zoekt zelf het dier op in de context om te weten of het al geplaatst is, en roept bij een klikadopteer(id)aan.
Als je een dier adopteert, moet je meteen het volgende zien:
- de knop wordt uitgeschakeld en toont
Heeft een thuis; - de
StatusBadgevan het dier springt naarGeplaatst; - de getallen bij Zoeken een thuis en Al geplaatst passen zich aan;
- het werkt ook als er een filter (bv. Katten) actief is.
De gekozen filter (soort in DierenOverzicht) blijft gewone lokale state. Niet alles hoort in een context: enkel gegevens die door veel componenten op verschillende plaatsen in de boom gebruikt worden.
Deel 3: Eigen hooks
Overal useContext(ThemeContext) en useContext(DierenContext) schrijven, is wat omslachtig.
- Exporteer uit
ThemeContext.tsxeen eigen hookuseThemedieuseContext(ThemeContext)teruggeeft. - Doe hetzelfde voor de dieren met een hook
useDiereninDierenContext.tsx. - Vervang alle
useContext-aanroepen in je componenten door deze twee hooks.
Extra
- Onthoud het gekozen thema in
localStorage, zodat de site na het herladen van de pagina in hetzelfde thema opent. - Voeg aan de
DierenContexteen functieannuleer(id)toe die een adoptie ongedaan maakt, en toon inAdopteerKnopeen knopAnnuleerbij een dier dat al geplaatst is. - Laat in de
Navnaast Onze dieren een teller zien met het aantal dieren dat nog een thuis zoekt (bv.Onze dieren (15)). Gebruik hiervoor jeuseDierenhook.