Zum Inhalt springen
React Anfänger 30 min

useState Hook

Meistere den useState Hook - den wichtigsten Hook in React. Lerne, wie du interaktiven State in deinen Komponenten verwaltest.

Aktualisiert:

useState Hook

Der useState-Hook ist der wichtigste Hook in React. Er gibt deinen Komponenten ein Gedaechtnis – sie koennen sich Werte merken und die Anzeige aktualisieren, wenn sich diese Werte aendern.

Was ist State?

State ist der veraenderliche Zustand einer Komponente. Waehrend Props von aussen kommen und nicht veraendert werden duerfen, gehoert State der Komponente selbst:

import { useState } from 'react';

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

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

useState verstehen

Die Syntax

const [stateVariable, setterFunction] = useState(initialValue);
  • stateVariable – der aktuelle Wert
  • setterFunction – die Funktion zum Aktualisieren des Werts
  • initialValue – der Anfangswert

Schritt fuer Schritt

import { useState } from 'react';

function NameInput() {
  // 1. State deklarieren mit Anfangswert ''
  const [name, setName] = useState('');

  // 2. State in JSX verwenden
  // 3. State mit Setter aktualisieren
  return (
    <div>
      <input
        value={name}
        onChange={(e) => setName(e.target.value)}
        placeholder="Dein Name"
      />
      <p>Hallo, {name || 'Fremder'}!</p>
    </div>
  );
}

Verschiedene State-Typen

Zahlen

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

  return (
    <div>
      <p>{count}</p>
      <button onClick={() => setCount(count + 1)}>Plus</button>
      <button onClick={() => setCount(count - 1)}>Minus</button>
      <button onClick={() => setCount(0)}>Reset</button>
    </div>
  );
}

Strings

function TextEditor() {
  const [text, setText] = useState('');

  return (
    <div>
      <textarea
        value={text}
        onChange={(e) => setText(e.target.value)}
        rows={5}
        cols={40}
      />
      <p>Zeichen: {text.length}</p>
    </div>
  );
}

Booleans

function ToggleSwitch() {
  const [isOn, setIsOn] = useState(false);

  return (
    <div>
      <button onClick={() => setIsOn(!isOn)}>
        {isOn ? 'AN' : 'AUS'}
      </button>
      <p>Der Schalter ist {isOn ? 'eingeschaltet' : 'ausgeschaltet'}.</p>
    </div>
  );
}

Arrays

function TodoList() {
  const [todos, setTodos] = useState([]);
  const [input, setInput] = useState('');

  function addTodo() {
    if (input.trim()) {
      setTodos([...todos, { id: Date.now(), text: input, done: false }]);
      setInput('');
    }
  }

  function removeTodo(id) {
    setTodos(todos.filter(todo => todo.id !== id));
  }

  function toggleTodo(id) {
    setTodos(todos.map(todo =>
      todo.id === id ? { ...todo, done: !todo.done } : todo
    ));
  }

  return (
    <div>
      <div>
        <input
          value={input}
          onChange={(e) => setInput(e.target.value)}
          onKeyDown={(e) => e.key === 'Enter' && addTodo()}
          placeholder="Neues Todo..."
        />
        <button onClick={addTodo}>Hinzufuegen</button>
      </div>
      <ul>
        {todos.map(todo => (
          <li key={todo.id}>
            <span
              onClick={() => toggleTodo(todo.id)}
              style={{
                textDecoration: todo.done ? 'line-through' : 'none',
                cursor: 'pointer'
              }}
            >
              {todo.text}
            </span>
            <button onClick={() => removeTodo(todo.id)}>X</button>
          </li>
        ))}
      </ul>
    </div>
  );
}

Objekte

function UserForm() {
  const [user, setUser] = useState({
    name: '',
    email: '',
    age: ''
  });

  function handleChange(field, value) {
    setUser({ ...user, [field]: value });
  }

  return (
    <form>
      <input
        placeholder="Name"
        value={user.name}
        onChange={(e) => handleChange('name', e.target.value)}
      />
      <input
        placeholder="E-Mail"
        value={user.email}
        onChange={(e) => handleChange('email', e.target.value)}
      />
      <input
        placeholder="Alter"
        type="number"
        value={user.age}
        onChange={(e) => handleChange('age', e.target.value)}
      />
      <pre>{JSON.stringify(user, null, 2)}</pre>
    </form>
  );
}

State richtig aktualisieren

Wichtig: Niemals State direkt aendern!

// FALSCH - State direkt aendern
const [user, setUser] = useState({ name: 'Max', age: 25 });
user.name = 'Anna'; // Niemals machen!

// RICHTIG - Neues Objekt erstellen
setUser({ ...user, name: 'Anna' });
// FALSCH - Array direkt aendern
const [items, setItems] = useState([1, 2, 3]);
items.push(4); // Niemals machen!

// RICHTIG - Neues Array erstellen
setItems([...items, 4]);

Array-Operationen mit State

OperationFalsch (mutiert)Richtig (neues Array)
Hinzufuegenarr.push(item)[...arr, item]
Entfernenarr.splice(i, 1)arr.filter(...)
Aendernarr[i] = newValarr.map(...)
Sortierenarr.sort()[...arr].sort()

Updater-Funktionen

Wenn der neue State vom vorherigen abhaengt, nutze eine Updater-Funktion:

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

  function incrementThree() {
    // FALSCH - count ist in allen drei Aufrufen derselbe Wert
    setCount(count + 1);
    setCount(count + 1);
    setCount(count + 1);
    // Ergebnis: count + 1 (nicht + 3!)

    // RICHTIG - Updater-Funktion bekommt den aktuellsten Wert
    setCount(prev => prev + 1);
    setCount(prev => prev + 1);
    setCount(prev => prev + 1);
    // Ergebnis: count + 3
  }

  return (
    <div>
      <p>{count}</p>
      <button onClick={incrementThree}>+3</button>
    </div>
  );
}

Mehrere State-Variablen

Du kannst useState mehrfach verwenden:

function SignupForm() {
  const [username, setUsername] = useState('');
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [agreeToTerms, setAgreeToTerms] = useState(false);

  const isValid = username.length >= 3 &&
                  email.includes('@') &&
                  password.length >= 8 &&
                  agreeToTerms;

  return (
    <form>
      <input
        placeholder="Benutzername (min. 3 Zeichen)"
        value={username}
        onChange={(e) => setUsername(e.target.value)}
      />
      <input
        type="email"
        placeholder="E-Mail"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
      />
      <input
        type="password"
        placeholder="Passwort (min. 8 Zeichen)"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
      />
      <label>
        <input
          type="checkbox"
          checked={agreeToTerms}
          onChange={(e) => setAgreeToTerms(e.target.checked)}
        />
        Ich stimme den AGB zu
      </label>
      <button disabled={!isValid}>Registrieren</button>
    </form>
  );
}

Lazy Initialization

Wenn der Anfangswert teuer zu berechnen ist, uebergib eine Funktion:

// SCHLECHT - wird bei JEDEM Render aufgerufen
const [data, setData] = useState(expensiveCalculation());

// GUT - wird nur beim ERSTEN Render aufgerufen
const [data, setData] = useState(() => expensiveCalculation());

// Praktisches Beispiel: LocalStorage lesen
const [theme, setTheme] = useState(() => {
  return localStorage.getItem('theme') || 'light';
});

Uebungen

  1. Baue einen Zaehler mit Plus, Minus und Reset-Buttons
  2. Erstelle ein Formular mit mehreren Feldern und Live-Vorschau
  3. Baue eine Einkaufsliste mit Hinzufuegen, Loeschen und Abhaken von Eintraegen

Was kommt als Naechstes?

Du beherrschst jetzt useState – der Grundstein fuer interaktive React-Apps. Im naechsten Kapitel lernst du Event Handling im Detail kennen – wie du auf Klicks, Tastendruecke und andere Benutzeraktionen reagierst.

Zusammenfassung

  • useState gibt Komponenten ein Gedaechtnis fuer veraenderliche Werte
  • Die Syntax ist const [value, setValue] = useState(initialValue)
  • Niemals State direkt aendern – immer den Setter verwenden
  • Fuer Objekte und Arrays immer neue Kopien erstellen (Spread-Operator)
  • Nutze Updater-Funktionen wenn der neue State vom vorherigen abhaengt
  • Lazy Initialization spart Performance bei teuren Berechnungen

Pro-Tipp: Halte deinen State so minimal wie moeglich. Wenn du einen Wert aus vorhandenem State berechnen kannst (z.B. filteredItems aus items und filter), dann speichere ihn nicht als separaten State – berechne ihn stattdessen bei jedem Render. Weniger State bedeutet weniger Bugs!

Zurück zum React Kurs