aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Webentwicklung

React useState: Grundlagen der State-Verwaltung

react usestate ist die grundlegendste Art, veränderliche Daten (State) innerhalb einer Funktionskomponente zu speichern. Ein Zähler, ein Formularfeld, ob ein Dropdown geöffnet oder geschlossen ist… alles, was sich durch Benutzerinteraktion ändert, ist State, und du musst ihn mit useState halten, damit React die Änderung auf dem Bildschirm widerspiegeln kann. Eine gewöhnliche Variable zu aktualisieren löst React nicht aus; useState hingegen speichert den Wert und rendert die Komponente neu, wenn er sich ändert.

Wie useState funktioniert

useState erhält einen Anfangswert und gibt ein Array mit zwei Elementen zurück: den aktuellen Wert und die Funktion, die ihn ändert. Mit Array-Destrukturierung benennen wir beide auf einmal:

import { useState } from "react";

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <button onClick={() => setCount(count + 1)}>
      Geklickt: {count}
    </button>
  );
}

Hier ist count der aktuelle Wert und setCount die Funktion, die ihn ändert. Die 0 in useState(0) wird nur beim ersten Render verwendet; bei späteren Renders merkt sich React den vorherigen Wert. Die Benennung liegt ganz bei dir, aber die Konvention [x, setX] ist Standard.

State niemals direkt mutieren

Der häufigste Fehler in React ist, State direkt zu mutieren. Der einzige Weg, State zu ändern, ist der Aufruf der Set-Funktion. Eine direkte Zuweisung wie unten aktualisiert den Bildschirm nicht:

// FALSCH — React bemerkt das nicht
count = count + 1;

// RICHTIG — löst ein erneutes Rendern aus
setCount(count + 1);

Dieselbe Regel gilt für Objekte und Arrays. Statt das bestehende Objekt zu ändern, erstellst du ein neues Objekt. Der Grund: React erkennt Änderungen per Referenzvergleich (ist der alte Wert derselbe wie der neue); wenn du dieselbe Referenz mutierst, merkt React nicht, dass sich etwas geändert hat.

const [user, setUser] = useState({ name: "Ada", alter: 30 });

// FALSCH
user.alter = 31;
setUser(user);

// RICHTIG — ein neues Objekt per Spread
setUser({ ...user, alter: 31 });

Funktionale Updates: warum und wann?

Statt der Set-Funktion direkt einen Wert zu übergeben, kannst du auch eine Funktion übergeben, die den vorherigen State als Argument erhält. Das nennt man ein funktionales Update, und es ist die sicherste Methode, wenn der neue Wert vom alten abhängt:

// hängt vom vorherigen Wert ab: die funktionale Form bevorzugen
setCount(prev => prev + 1);

Der Unterschied zeigt sich, wenn du den State im selben Ereignis mehrmals aktualisierst. Vergleiche diese beiden Beispiele:

// Dies erhöht den Zähler nur um 1
setCount(count + 1);
setCount(count + 1);
setCount(count + 1);

// Dies erhöht den Zähler um 3
setCount(prev => prev + 1);
setCount(prev => prev + 1);
setCount(prev => prev + 1);

Im ersten Block ist count der feste Wert aus diesem Render (zum Beispiel 0), daher berechnen alle drei Aufrufe 0 + 1. In der funktionalen Form erhält jeder Aufruf das Ergebnis des vorherigen Updates, sodass sich das Ergebnis korrekt aufsummiert.

Batching von Updates

React fasst mehrere State-Updates innerhalb desselben Event-Handlers zu einem einzigen Render zusammen; das nennt man Batching. Selbst wenn du also drei separate Set-Aufrufe machst, rendert die Komponente einmal neu und nicht dreimal. Das verbessert die Performance und verhindert, dass halbfertige Zwischenzustände auf dem Bildschirm erscheinen.

function handleClick() {
  setOffen(true);
  setZaehler(z => z + 1);
  setNachricht("aktualisiert");
  // alle drei werden in einem Render angewendet
}

Mit React 18 gilt dieses Verhalten nicht nur für Event-Handler, sondern auch für setTimeout, Promises und andere asynchrone Callbacks (automatisches Batching). Ein wichtiger Punkt: Direkt nach dem Aufruf der Set-Funktion enthält die State-Variable noch ihren alten Wert, weil das Update erst beim nächsten Render wirksam wird.

setCount(count + 1);
console.log(count); // immer noch der alte Wert — der Render ist noch nicht erfolgt

Praktische Muster mit Arrays und Objekten

Die Regel ist bei komplexem State dieselbe: kopieren, ändern, setzen. Häufige Muster:

  • Ein Element zu einer Liste hinzufügen: setItems(prev => [...prev, neu])
  • Aus einer Liste entfernen: setItems(prev => prev.filter(i => i.id !== id))
  • Ein Element aktualisieren: setItems(prev => prev.map(i => i.id === id ? { ...i, done: true } : i))

Wenn dein State stark verzweigt ist und viele voneinander abhängige Felder enthält, kann useReducer lesbarer sein als useState. Aber für die meisten alltäglichen Aufgaben reicht useState aus und ist die einfachste Lösung.

Häufige Fragen

Was ist der Unterschied zwischen useState und useRef?

useState rendert die Komponente neu, wenn es sich ändert; es ist für Daten gedacht, die auf dem Bildschirm erscheinen müssen. useRef speichert einen Wert über Renders hinweg, löst aber kein erneutes Rendern aus, wenn er sich ändert; es wird verwendet, um auf ein DOM-Element zuzugreifen oder einen Wert zu halten, der das Rendering nicht beeinflusst.

Darf ich useState in einer Schleife oder Bedingung aufrufen?

Nein. Alle Hooks müssen auf der obersten Ebene der Komponente aufgerufen werden, bei jedem Render in derselben Reihenfolge. Sie bedingt oder in einer Schleife aufzurufen zerstört Reacts Fähigkeit, States zuzuordnen, und führt zu einem Fehler.

Was, wenn der Anfangswert eine teure Berechnung ist?

Statt den Anfangswert direkt zu übergeben, übergib eine Funktion: useState(() => teureBerechnung()). Dieser „Lazy Initializer“ läuft nur beim ersten Render und wird bei späteren Renders nicht erneut berechnet.

State-Verwaltung richtig aufzusetzen ist die Grundlage einer wartbaren Oberfläche. Wenn du ein React-basiertes Projekt entwickelst oder eine bestehende Oberfläche verbessern möchtest, nimm Kontakt mit mir auf — lass uns gemeinsam eine solide Architektur aufbauen.

Bu kategorideki tüm yazılar →

Devamı için