Zum Inhalt springen

Aufgabe 11 - Komponenten-Baukasten

Zu Zen-Modus wechseln

Ihre ersten React-Komponenten: eine Oberfläche in wiederverwendbare Bausteine zerlegen, über typisierte Props verbinden und Listen deklarativ aus Daten ableiten (siehe Kapitel React-Grundlagen). Gebaut wird eine Klassen-Pinnwand mit Ankündigungskarten; der Baukasten-Gedanke wird am Ende bewiesen, indem dieselbe Karte unverändert in einem zweiten Kontext arbeitet.

  • Kapitel React-Grundlagen, Abschnitte Komponenten, Props, Listen und Bedingungen.
  • Node.js und ein frisches Next.js-Projekt, das Sie selbst anlegen: npx create-next-app@latest baukasten (TypeScript und App Router auswählen). Ihre Komponenten entstehen darin unter app/. Das ist ein bewusster Vorgriff auf Kapitel 8. Next.js I - Struktur und Routing, das Aufbau und Routing dieses Projekts systematisch behandelt; für diese Übung genügt das erzeugte Projekt als Gerüst, um React-Komponenten darin laufen zu lassen.
  • Sie zerlegen eine Oberfläche in eine sinnvolle Komponenten-Hierarchie.
  • Sie definieren Props als typisierte Verträge und rendern Listen mit korrekten Keys.
  • Sie leiten Anzeige aus Daten ab, statt sie zusammenzubauen.
  • Reproduktion: eine vorgezeichnete Komponente nach Muster umsetzen (Teil A).
  • Reorganisation und Transfer: die Zerlegung selbst entwerfen und mit Daten verbinden (Teile B und C).
  • Reflexion, Problemlösung und Urteilsbildung: Wiederverwendbarkeit nachweisen und Prop-Verträge bewerten (Teil D).

Die Übung ist auf etwa zwei Stunden ausgelegt. Teil D ist der Expertenteil.

So richten Sie die Pinnwand-Seite ein (einmal am Anfang, dann geht es los):

  1. Legen Sie im Projekt den Ordner app/pinnwand/ an und darin eine Datei page.tsx. Diese Seite erreichen Sie im Browser unter http://localhost:3000/pinnwand, sobald der Entwicklungsserver läuft (npm run dev).
  2. Jede Komponente schreiben Sie in eine eigene Datei, etwa app/pinnwand/AnnouncementCard.tsx. Solange eine Komponente nur Props anzeigt (Teile A bis C), braucht sie nichts Besonderes. Erst in Teil D, wo eine Karte per Klick aufklappt, kommt useState ins Spiel; diese Datei braucht dann ganz oben die Zeile "use client"; (sonst läuft sie als Server-Komponente und useState bricht ab).
  3. In page.tsx importieren Sie Ihre Komponenten und rendern die Pinnwand. Die Ankündigungen sind Objekte mit den Feldern aus interface Announcement (Titel, Text, Autor, Datum, Wichtigkeit; siehe Teil A). Die typisierte Datendatei lib/data.ts legen Sie erst in Teil B an; bis dahin genügt eine kurze Platzhalterliste direkt in page.tsx, damit die Seite anzeigbar ist:
import { Board } from "./Board";
// import { announcements } from "@/lib/data"; // wire this up in part B
const announcements = [
{
id: 1,
title: "Schulfest",
text: "Am Freitag ab 15 Uhr.",
author: "Direktion",
date: "2027-05-02",
importance: "important",
},
];
export default function PinnwandPage() {
return (
<main>
<Board announcements={announcements} />
</main>
);
}

In Teil B verschieben Sie die Daten dann nach lib/data.ts (mit interface Announcement) und ersetzen die Platzhalterliste durch den auskommentierten Import. Arbeiten Sie ansonsten Komponente für Komponente ab: Datei anlegen, in page.tsx (bzw. in die Elternkomponente) einhängen, im Browser ausprobieren, dann die nächste.

  1. Definieren Sie interface Announcement (Titel, Text, Autor, Datum als ISO-String, Wichtigkeit als "normal" | "important").
  2. Bauen Sie AnnouncementCard({ announcement }: { announcement: Announcement }): Titel als Überschrift, Text, darunter Autor und formatiertes Datum.
  3. Rendern Sie die Karte auf der Startseite zweimal mit verschiedenen Testdaten, um den Props-Mechanismus zu sehen.
  1. Skizzieren Sie auf Papier die Hierarchie der ganzen Pinnwand: Board mit Kartenliste, AnnouncementCard, darin ImportantBadge und AuthorLine. Notieren Sie an jeder Komponente, welche Props sie braucht; die Skizze ist Teil der Abgabe.
  2. Setzen Sie die Hierarchie um: fünf Ankündigungen als typisiertes Datenarray in einer eigenen Datei lib/data.ts (nicht in den Komponenten), Board rendert die Liste mit map.
  3. Beantworten Sie im Kommentar: Warum verlangt React ein key-Prop, und warum ist der Array-Index dafür eine schlechte Wahl?
  1. Wichtige Ankündigungen bekommen automatisch das Badge (&&-Rendern) und stehen oben: sortieren Sie die Daten vor dem Rendern (sortierte Kopie!), statt zwei Listen zu pflegen.
  2. Ergänzen Sie eine Kopfzeile “n Ankündigungen, davon m wichtig”: beide Zahlen werden beim Rendern aus dem Array berechnet, nirgends gespeichert.
  3. Halten Sie 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.
  1. Zweiter Einsatzort: Eine “Archiv”-Ansicht zeigt dieselben Karten kompakt (nur Titel und Datum). Steuern Sie das über ein optionales Prop compact?: boolean mit Default false; die Karte selbst bleibt eine Komponente.
  2. Dritter Einsatzort, härterer Test: Die Karte soll im Archiv beim Klick aufklappen können, ohne dass die Pinnwand-Variante sich ändert. Entscheiden Sie: Gehört dieser Zustand in die Karte oder in das Archiv? Implementieren Sie Ihre Antwort und begründen Sie sie in zwei Sätzen.
  3. Review des eigenen Prop-Vertrags: Prüfen Sie AnnouncementCard gegen zwei Kriterien: Braucht die Karte alles, was sie bekommt? Bekommt sie nichts, was sie sich selbst ausrechnen könnte? Dokumentieren Sie einen gefundenen Verstoß oder begründen Sie die Vertragsqualität.
  4. Beurteilen Sie in zwei Sätzen: Woran erkennt man an dieser Übung, dass Komponenten das UI-Gegenstück zu Funktionen sind?
  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 && <Badge /> in JSX?
  5. Wann lohnt ein optionales Prop wie compact, und wann wäre eine zweite Komponente ehrlicher?

Projektordner als Git-Repository und das Foto der Hierarchie-Skizze aus Teil B.