Zum Inhalt springen

Aufgabe 07-1a - Komponenten-Baukasten

Zu Zen-Modus wechseln
  • Du zerlegst eine Oberfläche in eine sinnvolle Komponenten-Hierarchie und skizzierst sie samt Props.
  • Du schreibst Komponenten in eigenen Dateien mit typisierten Props und exportierst sie benannt.
  • Du renderst Listen mit map und einem stabilen key und leitest Sortierung und Kennzahlen beim Rendern aus den Daten ab.
  • Du weist nach, dass eine Komponente in einem zweiten Kontext unverändert arbeitet, und prüfst ihren Prop-Vertrag.

Eine Pinnwand im Schulhaus hat niemand “programmiert”: Es gibt Zettel, die alle gleich aufgebaut sind, und jemand hängt sie auf. Genau so entsteht eine React-Oberfläche: Ein Baustein wird einmal entworfen und danach mit unterschiedlichen Daten immer wieder verwendet.

Du baust eine Klassen-Pinnwand mit Ankündigungskarten (siehe Kapitel React-Grundlagen, Einheiten 7.1 bis 7.3). Die Stufe Wesentlich_überwiegend passt nach Einheit 7.2 (JSX und Komponenten), die Stufe Wesentlich_vollständig nach Einheit 7.3 (Props, Listen und Events). Am Ende beweist du den Baukasten-Gedanken, indem dieselbe Karte unverändert in einem zweiten Kontext arbeitet.

Projektordner anlegen siehe https://qiz.at/projektordner

  • Lies vorher kurz https://qiz.at/assignmentsabgabe durch.

  • Nur vollständige Abgaben (siehe https://qiz.at/rules) können positiv bewertet werden.

  • Abgabe- und Testdetails siehe https://qiz.at/assignmentsabgabe

  • Die Übung liegt als Unterordner uebung-07-1a in deinem Jahres-Repository SJ26_27_4AHITM_SEW_<Benutzername>_exercises. Du legst ihn wie in Einheit 7.1 als Vite-Projekt an und arbeitest allein:

    Terminal-Fenster
    npm create vite@latest uebung-07-1a -- --template react-ts
    cd uebung-07-1a
    npm install
    npm run dev
  • Räum src/App.tsx auf: Der Beispielinhalt der Vorlage (Logos, Zähler) fliegt raus, übrig bleibt ein leeres Gerüst. Jede Komponente kommt in eine eigene Datei unter src/components/ und wird benannt exportiert (export function AnnouncementCard ...). Vite kennt keine @/-Kurzschreibweise; importiert wird relativ (./components/Board, ../data/announcements).

  • Schriftliche Antworten stehen als Kommentar im Code. npm run build muss fehlerfrei durchlaufen; node_modules/ kommt nicht ins Repository.

  • Next.js kommt erst in Kapitel 8 dazu: In einem Vite-Projekt läuft alles im Browser, es gibt keine Server-Komponenten und kein "use client".

  • Lege src/data/announcements.ts an und definiere darin interface Announcement mit id, Titel, Text, Autor, Datum als ISO-String und Wichtigkeit als "normal" | "important".
  • Schreib drei Komponenten in eigenen Dateien: AnnouncementCard({ announcement }: { announcement: Announcement }) zeigt den Titel als Überschrift und den Text; darunter AuthorLine mit Autor und formatiertem Datum; ImportantBadge vor dem Titel, aber nur bei wichtigen Ankündigungen.
  • Render die Karte in App.tsx zweimal mit zwei verschiedenen Testobjekten vom Typ Announcement, um den Props-Mechanismus zu sehen.
  • Provozier den Compiler einmal bewusst: Setz in einem Testobjekt importance: "wichtig". Notier die Meldung von npm run build als Kommentar und mach die Änderung rückgängig.
  • Skizzier auf Papier die Hierarchie der ganzen Pinnwand: App, Board mit Kartenliste, AnnouncementCard, darin ImportantBadge und AuthorLine. Notier an jeder Komponente, welche Props sie braucht.

Tipp: new Date(date).toLocaleDateString("de-AT") formatiert das Datum; die Formatierung gehört in AuthorLine, nicht als zusätzliches Prop. Typen holst du mit import type, sonst bricht der Build mit TS1484 ab (Einheit 7.3). Bleibt die Seite weiß, prüf die Schreibweise im JSX: Komponenten beginnen mit einem Großbuchstaben.

Vollständig, wenn:

  • npm run build ohne TypeScript-Fehler durchläuft, ohne any und ohne untypisierte Props.
  • jede der drei Komponenten in einer eigenen Datei unter src/components/ liegt, benannt wie die Komponente und benannt exportiert.
  • interface Announcement alle Felder abbildet, die Wichtigkeit als Union Type, und in src/data/announcements.ts liegt.
  • das Badge nur bei wichtigen Ankündigungen erscheint und die Compiler-Meldung zu "wichtig" als Kommentar notiert ist.
  • die Hierarchie-Skizze vorhanden ist, mit Props an jeder Komponente.

Wie unter Allgemein, dazu ein Foto der Hierarchie-Skizze.

Für alle, die in der Einheit mit den Schritten oben fertig sind bzw. optional (= freiwillig), wenn du in der Einheit nicht fertig wirst.

Erweitere (siehe Erweitern in https://qiz.at/rules) den vollständigen Teil der vorherigen Stufe dieses Projekts (ändere oder lösche nur, was für diese Aufgabe unbedingt notwendig ist):

  • Leg in src/data/announcements.ts fünf Ankündigungen als typisiertes Array announcements an (nicht in den Komponenten). Ersetz die Testobjekte in App.tsx durch eine Komponente Board, die die Daten als Prop bekommt und die Karten mit map rendert.
  • Beantworte als Kommentar: Warum verlangt React ein key-Prop, und warum ist der Array-Index dafür eine schlechte Wahl?
  • Wichtige Ankündigungen stehen oben: Sortier die Daten vor dem Rendern (sortierte Kopie!), statt zwei Listen zu pflegen.
  • Ergänz eine Kopfzeile “n Ankündigungen, davon m wichtig”: Beide Zahlen werden beim Rendern aus dem Array berechnet, nirgends gespeichert.
  • Halte in drei Kommentarsätzen fest, wie dieselbe Pinnwand mit direkter DOM-Manipulation aussähe (Elemente erzeugen, einhängen, bei Änderung wiederfinden und aktualisieren) und was React davon übernimmt.

Tipp: sort verändert das Array, auf dem es aufgerufen wird; arbeite deshalb auf einer Kopie: [...announcements].sort(...). Die Liste zeigt nichts an? Mit runden Klammern nach dem Pfeil ((a) => (<li ...>)) wird der Rückgabewert automatisch geliefert, mit geschweiften brauchst du ein return. Das key-Attribut gehört an das äußerste Element innerhalb von map.

Vollständig, wenn:

  • die fünf Ankündigungen in src/data/announcements.ts liegen und Board sie mit map und einem stabilen key aus den Daten (nicht dem Index) rendert.
  • die Antwort zur Key-Frage dokumentiert ist.
  • Sortierung und Kennzahlen beim Rendern abgeleitet sind; es gibt keine zweite gespeicherte Liste und keinen Zähler im Code.
  • keine Komponente auf document. zugreift und der Vergleich mit der DOM-Manipulation in drei Sätzen notiert ist.

Wie unter Allgemein, dazu ein Screenshot der laufenden Pinnwand inklusive Browser-Adresszeile.

Für alle, die in der Einheit mit den Schritten oben fertig sind bzw. optional (= freiwillig), wenn du in der Einheit nicht fertig wirst.

Erweitere (siehe Erweitern in https://qiz.at/rules) den vollständigen Teil der vorherigen Stufe dieses Projekts (ändere oder lösche nur, was für diese Aufgabe unbedingt notwendig ist):

  • Zweiter Einsatzort: Eine Komponente Archive zeigt dieselben Karten kompakt (nur Titel, Badge und Autorzeile). Steuer das über ein optionales Prop compact?: boolean mit Standardwert false; die Karte bleibt eine Komponente, und die Pinnwand-Variante ändert sich nicht.
  • Review des eigenen Prop-Vertrags: Prüf AnnouncementCard gegen zwei Kriterien. Braucht die Karte alles, was sie bekommt? Bekommt sie nichts, was sie sich selbst ausrechnen könnte? Dokumentier einen gefundenen Verstoß samt Korrektur oder begründe die Vertragsqualität als Kommentar.

Tipp: Ein Prop ohne Fragezeichen und ohne Standardwert zwingt dich, jede bestehende Verwendungsstelle zu ändern. Genau das darf der zweite Einsatzort nicht verlangen.

Vollständig, wenn:

  • compact optional mit Standardwert ist, das Archiv dieselbe Karte verwendet und die Pinnwand unverändert bleibt.
  • das Prop-Vertrags-Review nachvollziehbar dokumentiert ist.

Wie unter Allgemein.

Für alle, die in der Einheit mit den Schritten oben fertig sind bzw. optional (= freiwillig), wenn du in der Einheit nicht fertig wirst.

Erweitere (siehe Erweitern in https://qiz.at/rules) den vollständigen Teil der vorherigen Stufe dieses Projekts (ändere oder lösche nur, was für diese Aufgabe unbedingt notwendig ist):

  • Härterer Test: Die Karte soll im Archiv beim Klick aufklappen können (dann mit Text), ohne dass sich die Pinnwand-Variante ändert. Entscheide: Gehört dieser Zustand in die Karte oder in das Archiv? Setz deine Antwort mit useState um und begründe sie in zwei Sätzen.
  • Beurteile in zwei Sätzen: Woran erkennt man an dieser Übung, dass Komponenten das Gegenstück der Oberfläche zu Funktionen sind?

Tipp: useState kommt erst in Einheit 7.4 ausführlich; für diese Stufe genügt const [expanded, setExpanded] = useState(false); ganz oben in der Komponente, nicht in einem if. Für die Entscheidung hilft die Frage: Wer außer der Karte liest oder ändert diesen Zustand?

Vollständig, wenn:

  • das Aufklappen im Archiv funktioniert und die Pinnwand-Variante unverändert ist.
  • die Zustandsentscheidung mit einer Begründung belegt ist, die zur Umsetzung passt.
  • die Beurteilung zu Komponenten und Funktionen stichhaltig ist.

Wie unter Allgemein.

  1. Was sind Props, und warum darf eine Komponente ihre eigenen Props nicht ändern?
  2. Wozu braucht React das key-Prop bei Listen?
  3. Warum wird die Wichtig-Sortierung vor dem Rendern berechnet statt als zweite Liste gespeichert?
  4. Was bewirkt bedingung && <ImportantBadge /> in JSX?
  5. Wann lohnt ein optionales Prop wie compact, und wann wäre eine zweite Komponente ehrlicher?
  6. Warum muss ein Komponentenname mit einem Großbuchstaben beginnen?

Durchschnittlich bis Wesentlich_vollständig: ca. 100 min

  • Oliver Maurhart (MAO)
  • Michael Gabriel (GAM)

CC-BY-SA

https://qiz.at/rules