Aufgabe 07-4a - State-Training
Lernziele
Abschnitt betitelt „Lernziele“- Du entscheidest begründet, welche Werte State sind und welche beim Rendern berechnet werden.
- Du aktualisierst State nur über den Setter, mit der Funktionsform, wenn der neue Wert vom alten abhängt, und Arrays immutabel.
- Du baust ein kontrolliertes Formularfeld mit live abgeleiteter Anzeige.
- Du hebst gemeinsamen State in den nächstgemeinsamen Vorfahren und meldest Änderungen über Callback-Props.
Ausgangslage
Abschnitt betitelt „Ausgangslage“Ein Getränkeautomat merkt sich, wie viel Geld eingeworfen wurde, sonst könnte er nicht entscheiden, ob er etwas herausgibt. Genau diese Frage stellt sich bei jeder Oberfläche: Was muss sich das Programm merken, und was kann es jederzeit ausrechnen? Wer sie falsch beantwortet, baut Anzeigen, die irgendwann nicht mehr zusammenpassen.
An vier kleinen Komponenten trainierst du den Umgang mit State (siehe Kapitel React-Grundlagen, Einheiten 7.4 und 7.5). Die Stufe Wesentlich_überwiegend passt nach Einheit 7.4 (State und Render-Kreislauf), die Stufe Wesentlich_vollständig nach Einheit 7.5 (Datenfluss und Formulare); die Stufen PlusPlus und MandalorianPlus heben State nach oben.
Allgemein
Abschnitt betitelt „Allgemein“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-4ain deinem Jahres-RepositorySJ26_27_4AHITM_SEW_<Benutzername>_exercises, angelegt wieuebung-07-1amitnpm create vite@latest uebung-07-4a -- --template react-ts. Du arbeitest allein. -
Leg die Komponente
src/components/StateTraining.tsxan und render sie ausApp.tsx; sie ist die Klammer um die Übungskomponenten. Jede Übungskomponente kommt in eine eigene Datei untersrc/components/und wird inStateTraininguntereinander gerendert:import { Thumbs } from "./Thumbs";export function StateTraining() {return (<section><Thumbs />{/* the other components get added here as you build them */}</section>);} -
Schriftliche Antworten stehen als Kommentar im Code, die State-Tabelle in der
README.mddes Projekts.npm run buildmuss fehlerfrei durchlaufen;node_modules/kommt nicht ins Repository.
Wesentlich_überwiegend
Abschnitt betitelt „Wesentlich_überwiegend“Aufgabe
Abschnitt betitelt „Aufgabe“Thumbs, ein Daumen-hoch/-runter-Zähler: zwei Buttons und dazwischen die Differenz.- Entscheide vor dem Code: ein State (die Differenz) oder zwei (
upunddown)? Schreib Wahl und Begründung als Kommentar über die Komponente. - Die Klicks verwenden die Funktionsform des Setters:
setUp((current) => current + 1). - Die Differenz wird bei zwei States berechnet (
up - down), nicht gespeichert.
- Entscheide vor dem Code: ein State (die Differenz) oder zwei (
- Pflicht-Experiment: Schreib in den Klick-Handler von
Thumbsdirekt nach dem Setter einconsole.log(up). Beobachte den Wert in der Konsole und erklär ihn in einem Kommentarsatz. DicePair, zwei Würfel und ein “Würfeln”-Button.- Zwei States für die Augenzahlen (1 bis 6); der Button setzt beide neu (
Math.floor(Math.random() * 6) + 1). - Bei einem Pasch erscheint “Pasch!”. Diese Meldung ist kein eigener State, sondern wird aus den beiden Würfelwerten berechnet.
- Begründe als Kommentar, welcher Fehler bei einem zusätzlichen
isDouble-State entstehen könnte.
- Zwei States für die Augenzahlen (1 bis 6); der Button setzt beide neu (
Tipp: Was müsstest du ändern, wenn später “wie viele Stimmen insgesamt?” dazukommt? Das ist ein Argument für zwei States. “Rendered more hooks than during the previous render” heißt: Ein
useStatesteht in einemifoder einer Schleife.
Bewertungskriterien
Abschnitt betitelt „Bewertungskriterien“Vollständig, wenn:
npm run buildohne TypeScript-Fehler durchläuft und beide Komponenten überStateTrainingbedienbar sind.- jeder
useState-Aufruf auf oberster Ebene der Komponente steht und Änderungen nur über Setter laufen. - Differenz und Pasch-Meldung beim Rendern berechnet werden und keinen eigenen State haben.
- das Experiment zum Setter-Wert durchgeführt und richtig erklärt ist, ebenso die
isDouble-Frage.
Wie unter Allgemein.
Wesentlich_vollständig
Abschnitt betitelt „Wesentlich_vollständig“Für alle, die in der Einheit mit den Schritten oben fertig sind bzw. optional (= freiwillig), wenn du in der Einheit nicht fertig wirst.
Aufgabe
Abschnitt betitelt „Aufgabe“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):
CharacterCounter, ein Textfeld mit Live-Zähler wie bei einer Kurznachricht.- Ein
<textarea>als controlled component:valueaus dem State,onChangeschreibt jede Eingabe zurück. - Darunter live “42 / 280 Zeichen”; die Länge ist
text.length, kein eigener State. - Ab 260 Zeichen bekommt die Anzeige eine Warnfarbe über eine abgeleitete CSS-Klasse (
className={text.length > 260 ? "warn" : ""}), ohnedocument.querySelector.
- Ein
ShoppingList: Ein Eingabefeld plus “Hinzufügen”-Button hängt einen Eintrag an, ein Klick auf einen Eintrag entfernt ihn.- Zwei States: der Text des Eingabefelds (
string) und die Einträge (string[]). Füg immutabel hinzu ([...items, newItem]) und entferne immutabel (items.filter(...)). - Pflicht-Experiment: Bau das Hinzufügen absichtlich einmal mit
items.push(newItem). Beobachte, dass die Anzeige sich nicht aktualisiert, und erklär im Kommentar, warum React die Änderung nicht bemerkt. Danach zurück zur korrekten Version. - Der Button ist deaktiviert, solange das Eingabefeld leer ist (
disabled={text.trim() === ""}).
- Zwei States: der Text des Eingabefelds (
- Erstell in der
README.mdeine State-Tabelle für alle vier Komponenten: Variable, echter State oder abgeleitet, Begründung in Stichworten.
Tipp: Ein
valueohneonChangefriert das Feld ein, und React warnt in der Konsole.disabled="false"ist ein nicht leerer String und damit wahr; der Wert gehört in geschweifte Klammern. Prüfkriterium für echten State: Er entsteht nur durch eine Benutzeraktion und lässt sich aus nichts anderem berechnen.
Bewertungskriterien
Abschnitt betitelt „Bewertungskriterien“Vollständig, wenn:
- alle vier Komponenten über
StateTrainingerreichbar und bedienbar sind. - das Textfeld kontrolliert ist und Zeichenzahl, Warnklasse und
disabledbeim Rendern berechnet werden. - Arrays nur immutabel ersetzt werden, nie mit
pushodersplice, und daspush-Experiment richtig erklärt ist. - die State-Tabelle alle vier Komponenten abdeckt und jede Einstufung begründet.
Wie unter Allgemein, dazu ein Screenshot der laufenden Seite inklusive Browser-Adresszeile.
PlusPlus Aufgabe
Abschnitt betitelt „PlusPlus Aufgabe“Für alle, die in der Einheit mit den Schritten oben fertig sind bzw. optional (= freiwillig), wenn du in der Einheit nicht fertig wirst.
Aufgabe
Abschnitt betitelt „Aufgabe“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):
- Über allen vier Komponenten soll eine Leiste “Interaktionen gesamt: n” jede Aktion in jeder Komponente mitzählen. Entwirf zuerst auf Papier: Wo muss dieser Zähler leben, und warum kann er in keiner der vier Komponenten selbst wohnen? Notier die Antwort in Stichworten als Kommentar.
- Setz das Muster State heben um: Der Zähler-State wandert in
StateTraining. Jede der vier Komponenten bekommt eine Callback-ProponInteraction: () => voidund ruft sie bei jeder Aktion auf; kein Kind kennt den Zähler selbst.
Tipp:
onInteraction()gehört in den Handler, nicht in den Rumpf der Komponente; dort liefe es bei jedem Rendern.
Bewertungskriterien
Abschnitt betitelt „Bewertungskriterien“Vollständig, wenn:
- der Zähler in
StateTrainingwohnt und alle vier Kinder über eine Callback-Prop melden. - kein Kind den Zähler kennt und die Entwurfsbegründung notiert ist.
Wie unter Allgemein.
MandalorianPlus Aufgabe
Abschnitt betitelt „MandalorianPlus Aufgabe“Für alle, die in der Einheit mit den Schritten oben fertig sind bzw. optional (= freiwillig), wenn du in der Einheit nicht fertig wirst.
Aufgabe
Abschnitt betitelt „Aufgabe“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):
- Die Leiste zeigt zusätzlich, welche Komponente zuletzt benutzt wurde. Erweitere die Signatur zu
onInteraction(source: string); jedes Kind meldet seinen Namen mit. - Begründe in zwei Sätzen, warum die Alternative, dass jedes Kind direkt in eine globale Variable schreibt, den Einweg-Datenfluss von React zerstören würde.
- Beurteile in zwei Sätzen: Nach welcher Regel entscheidest du ab jetzt, auf welcher Ebene der Hierarchie ein State wohnt?
Tipp: Denk bei der globalen Variable an den Render-Kreislauf aus Einheit 7.4: Was löst eine Änderung an einer gewöhnlichen Variable aus?
Bewertungskriterien
Abschnitt betitelt „Bewertungskriterien“Vollständig, wenn:
- die Leiste Gesamtzahl und zuletzt benutzte Komponente korrekt anzeigt.
- die Begründung zur globalen Variable den fehlenden Render-Auslöser oder den verlorenen Einweg-Datenfluss benennt.
- die Hierarchie-Regel in eigenen Worten formuliert ist.
Wie unter Allgemein.
Wissenscheck
Abschnitt betitelt „Wissenscheck“- Woran erkennst du, dass ein Wert kein State sein sollte?
- Warum bewirkt
items.push(...)keine Aktualisierung der Anzeige? - Was ist der Vorteil der Setter-Funktionsform
setCount((c) => c + 1)? - Warum zeigt ein
console.logdirekt nach dem Setter noch den alten Wert? - Was bedeutet “Props runter, Events rauf” konkret in der Stufe PlusPlus?
- Welche zwei Wahrheiten können bei einem redundanten
isDouble-State auseinanderlaufen?
Zeit dafür
Abschnitt betitelt „Zeit dafür“Durchschnittlich bis Wesentlich_vollständig: ca. 100 min
Autoren
Abschnitt betitelt „Autoren“- Oliver Maurhart (MAO)
- Michael Gabriel (GAM)
CC-BY-SA