Menu

Kontrollierte vs. unkontrollierte Komponenten in React

Ein kontrolliertes Input bekommt seinen Wert aus dem React-State und ändert sich nur über onChange. Ein unkontrolliertes Input hält seinen Wert selbst im DOM, und du liest ihn mit einer Ref oder FormData. Lerne den Unterschied, die häufigen Warnungen und wann du was nimmst.

Diese Seite enthält ausführbare Editoren - bearbeiten, ausführen und Ausgabe sofort sehen.

Eine kontrollierte Komponente ist ein Formularelement, dessen Wert im React-State lebt: Du übergibst value und aktualisierst den State in onChange, also entscheidet React, was das Input zeigt. Eine unkontrollierte Komponente hält ihren Wert im DOM, wie reines HTML: Du übergibst einen Startwert defaultValue und liest den aktuellen Wert später über eine Ref oder FormData.

Tippe in beide Inputs. Der Absatz folgt dem ersten bei jedem Tastendruck, weil jede Änderung State setzt und erneut rendert. Das zweite Input ändert sich nur im DOM; React rendert nicht, und du siehst seinen Wert erst, wenn „Read both“ danach fragt.

Kontrollierte Inputs

Bei einem kontrollierten Input ist der React-State die einzige Quelle der Wahrheit. Der Ablauf bei jedem Tastendruck ist:

  1. Jemand tippt, und der Browser feuert ein Input-Event.
  2. Dein onChange-Handler liest e.target.value und ruft den Setter auf.
  3. React rendert erneut und schreibt den neuen State zurück in den value des Inputs.

Weil dein Code mitten in dieser Schleife sitzt, kannst du Dinge tun, die ein unkontrolliertes Input nicht kann: Zeichen ablehnen oder umformen, den Wert woanders anzeigen, einen Button deaktivieren, bis der Wert gültig ist, oder den Wert aus dem Code setzen (ein „Leeren“-Button, ein Vorschlag, den jemand anklickt).

Versuche, Buchstaben zu tippen: Sie erscheinen nie, weil der Handler alles entfernt, was keine Ziffer ist, bevor er State setzt. Der Button Verify bleibt deaktiviert, bis es genau sechs Ziffern sind.

Kontrolliert ist das, was die Formularbeispiele auf der Seite zu Formularen nutzen, und es ist in den meisten React-Codebasen die Standardwahl.

Unkontrollierte Inputs

Ein unkontrolliertes Input funktioniert wie reines HTML. React rendert es einmal mit defaultValue (oder defaultChecked für Checkboxen und Radios) und lässt es dann in Ruhe. Um den Wert zu lesen, hältst du entweder eine Ref auf das Element oder liest beim Absenden alle benannten Felder des Formulars mit FormData.

Es gibt keinen State für die Felder und kein onChange. Die Werte werden erst eingesammelt, wenn das Formular abgesendet wird. Entferne das Häkchen und sende erneut: Der Schlüssel subscribe verschwindet, weil eine nicht angehakte Checkbox gar nicht Teil von FormData ist.

defaultValue nach dem ersten Render zu ändern bewirkt am Input nichts, weil React es nur beim Erstellen des Elements anwendet. Um ein unkontrolliertes Formular zurückzusetzen, ruf e.target.reset() auf oder gib dem Formular einen neuen key, damit React frische Inputs erzeugt.

Ein Input, in das du nicht tippen kannst

Wenn du value übergibst, aber kein onChange, ist das Input kontrolliert, aber nichts aktualisiert je den State. React schreibt nach jedem Tastendruck denselben Wert zurück, also wirkt das Input eingefroren.

Tippe in jedes Feld. Das erste ändert sich nicht. Das zweite ist die Lösung für ein kontrolliertes Input, und während du dort tippst, folgen ihm das erste und das letzte Feld, weil alle drei denselben State lesen. Das dritte nimmt Eingaben an, weil es unkontrolliert ist. Das vierte sagt absichtlich, dass es nicht bearbeitet werden kann.

In der Entwicklung loggt React für das erste Input eine Warnung: „You provided a value prop to a form field without an onChange handler“. Die Vorschau läuft wie ein Produktions-Build, also siehst du diese Warnung hier nicht, aber auf deinem eigenen Dev-Server schon.

Von unkontrolliert zu kontrolliert wechseln

React entscheidet anhand von value, ob ein Input kontrolliert ist. Wenn value undefined oder null ist, ist das Input unkontrolliert. Ein Input, dessen value als undefined beginnt und später zu einem String wird, wechselt also im Laufe seines Lebens von unkontrolliert zu kontrolliert, und React warnt in der Entwicklung: „A component is changing an uncontrolled input to be controlled“.

Die Warnung zeigt auf einen echten Bug. Der umgekehrte Weg, von einem String zu undefined, macht das Input wieder unkontrolliert, und React hört auf, hineinzuschreiben.

Tippe etwas in beide Inputs und drück jeden Clear-Button. Das zweite Input wird leer. Das erste behält seinen Text: Den State auf undefined zu setzen hat es unkontrolliert gemacht, also bestimmt React nicht mehr, was es zeigt.

Die übliche Quelle für undefined sind Daten, die noch nicht geladen sind (value={user.name}, bevor der Nutzer da ist), oder ein Objektfeld, das es noch nicht gibt. Zwei Lösungen:

const [name, setName] = useState('');   // start with a string
<input value={user?.name ?? ''} />       // or fall back to one

Für Checkboxen gilt dieselbe Regel für checked: Starte mit false, nicht mit undefined.

Datei-Inputs sind immer unkontrolliert

Ein <input type="file"> kann nicht kontrolliert werden, weil Browser einer Seite nicht erlauben, seinen Wert zu setzen (eine Seite, die Dateien auf deiner Festplatte auswählen könnte, wäre eine Sicherheitslücke). Lies die gewählten Dateien in onChange aus e.target.files oder beim Absenden über eine Ref.

Wähle eine oder zwei Dateien von deinem Computer; nichts wird hochgeladen, das Beispiel listet nur Namen und Größen. Der einzige Wert, den du an einem Datei-Input setzen darfst, ist der leere String, und so setzt der Clear-Button es zurück.

Wann du was wählst

KontrolliertUnkontrolliert
Wert lebt inReact-StateDem DOM
Startwert setzenvalue / checkeddefaultValue / defaultChecked
Wert lesenJederzeit, aus dem StateMit einer Ref oder FormData beim Absenden
Rendert bei jedem TastendruckJaNein
Wert aus dem Code ändernState setzenÜber eine Ref ins DOM schreiben
Gut fürLive-Validierung, Formatierung, abhängige FelderEinfache Formulare, die beim Absenden gelesen werden, Datei-Inputs, Form Actions

Wähle kontrolliert, wenn der Bildschirm schon beim Tippen auf den Wert reagieren muss. Wähle unkontrolliert, wenn du die Werte erst am Ende brauchst, und so funktionieren auch die Form Actions in React 19: <form action={fn}> gibt deiner Funktion ein FormData und setzt danach die unkontrollierten Felder zurück.

Bei jedem Tastendruck zu rendern klingt teuer, ist für ein normales Formular aber kein Problem. Zum Problem wird es erst, wenn ein großer, langsamer Baum mit dem Input neu rendert; dann halte den State nah am Input oder verschiebe den langsamen Teil in eine eigene Komponente.

Dieselben zwei Wörter beschreiben auch deine eigenen Komponenten. Eine Komponente, die ihren Wert und ein onChange über Props von ihrem Elternteil bekommt, wird vom Elternteil kontrolliert; eine, die ihren eigenen State hält, ist unkontrolliert. State nach oben zu verschieben, um eine Komponente kontrolliert zu machen, ist das Thema von State nach oben verlagern.

Häufig gestellte Fragen

Was ist eine kontrollierte Komponente in React?

Ein Formularelement, dessen aktueller Wert aus dem React-State kommt, gesetzt mit value (oder checked) und aktualisiert über onChange. Der React-State ist die einzige Quelle der Wahrheit, also kennst du den Wert immer und kannst ihn aus dem Code ändern.

Was ist eine unkontrollierte Komponente in React?

Ein Formularelement, das seinen Wert selbst im DOM hält, wie reines HTML. Du gibst ihm mit defaultValue (oder defaultChecked) einen Startwert und liest den aktuellen Wert, wenn du ihn brauchst, über eine Ref oder FormData beim Absenden.

Warum kann ich in mein React-Input nicht tippen?

Du hast value ohne onChange übergeben. Das Input ist kontrolliert, also setzt React nach jedem Tastendruck wieder den Wert aus dem State ein. Füge ein onChange hinzu, das den State aktualisiert, wechsle zu defaultValue oder füge readOnly hinzu, wenn es sich wirklich nicht ändern soll.

Wie behebe ich „A component is changing an uncontrolled input to be controlled“?

Der value des Inputs war anfangs undefined (oder null) und wurde später zu einem String. Sorge dafür, dass er immer ein String ist: Starte den State mit '' oder schreib value={name ?? ''}.

Sollte ich kontrollierte oder unkontrollierte Inputs nutzen?

Nutze kontrollierte Inputs, wenn die UI schon beim Tippen auf den Wert reagiert: Validierung, Formatierung, ein deaktivierter Button, voneinander abhängige Felder. Nutze unkontrollierte Inputs, wenn du die Werte erst beim Absenden brauchst, und für Datei-Inputs, die immer unkontrolliert sind.

Illustration der Programmiersprachen bei Coddy

Lerne mit Coddy zu programmieren

LOS GEHT'S