React key-Prop Fallstricke: Warum Index als Key oft falsch ist
AI generated
{ }
React 19 · Listen · Reconciliation
React key-Prop Fallstricke
Warum Index als Key oft falsch ist

Der Array-Index als key-Wert funktioniert scheinbar problemlos, bis eine Liste sortiert, gefiltert oder verändert wird. Dann recycelt React internen Komponenten-State zwischen den falschen Elementen, mit teils gravierenden, schwer nachvollziehbaren Folgen.

13 Min. Lesezeit Reconciliation Listen-Rendering Debugging

1. Wozu der key-Prop eigentlich dient

React nutzt den key-Prop, um Elemente in einer Liste über mehrere Renders hinweg eindeutig zu identifizieren. Beim Vergleich des vorherigen mit dem neuen virtuellen DOM-Baum, der sogenannten Reconciliation, ordnet React jedes Element im neuen Baum anhand seines key-Werts einem Element im alten Baum zu. Stimmt der key überein, geht React davon aus, dass es sich um dieselbe logische Instanz handelt, und behält den internen State sowie den DOM-Knoten dieser Instanz bei, statt sie neu zu erzeugen.

Ohne stabile key-Werte kann React Elemente nicht zuverlässig über Renders hinweg identifizieren und greift auf Positions-basierte Heuristiken zurück, die schnell zu falschen Zuordnungen führen. Der key ist also kein reines Performance-Hinweis, sondern ein Identitätsmerkmal, das direkt beeinflusst, welche Komponenten-Instanz welchen State behält.

2. Index als key: die naheliegende, aber trügerische Lösung

Wenn eine Liste keine offensichtliche eindeutige ID besitzt, greifen viele Entwickler intuitiv zum Array-Index als key, weil er immer verfügbar und garantiert eindeutig innerhalb des aktuellen Renders ist. Solange sich die Reihenfolge und Zusammensetzung der Liste nie ändert, funktioniert das auch tatsächlich unauffällig, weil Index und logische Identität in diesem Fall zufällig übereinstimmen.

Das Problem entsteht, sobald sich die Liste verändert: Wird ein Element am Anfang eingefügt, gelöscht oder die Reihenfolge vertauscht, verschiebt sich der Index jedes nachfolgenden Elements, obwohl die eigentliche logische Identität der Elemente gleich geblieben ist. React sieht dann an Index 0 ein 'anderes' Element als vorher, obwohl dort inhaltlich dasselbe Element mit verschobener Position steht, und ordnet React-internen State entsprechend falsch zu.

3. Konkretes Bug-Beispiel: Formularfelder in einer Todo-Liste

Ein besonders anschauliches Beispiel ist eine Todo-Liste, bei der jedes Element ein eigenes, unkontrolliertes Eingabefeld für Notizen enthält. Löscht man das erste Element aus der Liste, während Index als key verwendet wird, behält React fälschlicherweise den DOM-Knoten und den internen State an Index 0 bei, weil React glaubt, es handle sich weiterhin um dieselbe Komponente. Der eingegebene Notiztext bleibt im Eingabefeld stehen, gehört inhaltlich aber jetzt zum falschen Todo-Eintrag.

Dieser Effekt ist deshalb so tückisch, weil er sich nicht als Absturz oder Fehlermeldung zeigt, sondern als stille, semantisch falsche Datenanzeige. Nutzer bemerken oft erst spät, dass eine Notiz plötzlich am falschen Eintrag hängt, und der Fehler lässt sich ohne Wissen um die Reconciliation-Mechanik nur schwer nachvollziehen.


function TodoList({ todos, onDelete }) {
  return (
    <ul>
      {todos.map((todo, index) => (
        // FALSCH: index als key -- Notiz-State wird beim Loeschen
        // dem falschen Todo zugeordnet
        <li key={index}>
          <span>{todo.title}</span>
          <input type="text" placeholder="Notiz..." />
          <button onClick={() => onDelete(todo.id)}>Loeschen</button>
        </li>
      ))}
    </ul>
  );
}

4. Die Lösung: stabile, inhaltliche IDs als key

Der korrekte Ansatz ist, eine stabile, inhaltlich verankerte ID zu verwenden, typischerweise eine Datenbank-ID oder eine beim Erzeugen des Elements einmalig generierte UUID. Diese ID bleibt über die gesamte Lebensdauer des logischen Elements unverändert, unabhängig davon, an welcher Position es sich in der Liste gerade befindet, und React kann dadurch Elemente auch nach Umsortierung, Filterung oder Löschung korrekt identifizieren.

Mit einer stabilen ID als key bleibt im obigen Todo-Beispiel der Notiztext korrekt am ursprünglichen Todo-Eintrag hängen, selbst wenn ein anderes Element aus der Liste entfernt wird. React erkennt anhand der ID zuverlässig, welche Komponenten-Instanz gelöscht wurde und welche unverändert an ihrer neuen Position weiterexistiert.


function TodoList({ todos, onDelete }) {
  return (
    <ul>
      {todos.map((todo) => (
        // RICHTIG: stabile todo.id als key
        <li key={todo.id}>
          <span>{todo.title}</span>
          <input type="text" placeholder="Notiz..." />
          <button onClick={() => onDelete(todo.id)}>Loeschen</button>
        </li>
      ))}
    </ul>
  );
}

5. Ein zweites Beispiel: Animationen und CSS-Transitions

Ähnliche Probleme treten bei Listen mit Animationsbibliotheken auf, die auf Mount- und Unmount-Ereignisse einzelner Elemente reagieren. Verwendet eine sortierbare Liste den Index als key, erkennt die Animationsbibliothek beim Umsortieren keine tatsächliche Bewegung eines Elements, sondern nur eine inhaltliche Änderung an derselben Position, weil aus React-Sicht formal dieselbe Komponenten-Instanz an Index 0 bestehen bleibt.

Das Ergebnis ist, dass Elemente beim Umsortieren nicht sichtbar von Position A nach Position B animieren, sondern lediglich ihr Textinhalt an Ort und Stelle wechselt, was für Nutzer verwirrend wirkt und den Zweck der Animation komplett verfehlt. Mit einer stabilen ID als key erkennt React dagegen, dass sich eine bestehende Komponenten-Instanz nur an eine andere Position im Baum verschoben hat, wodurch Animationsbibliotheken den Übergang korrekt abbilden können.

6. Die Ausnahme: statische, niemals veränderte Listen

Index als key ist nicht in jedem Fall problematisch. Wenn eine Liste garantiert statisch ist, also niemals sortiert, gefiltert, eingefügt oder gelöscht wird und die Elemente selbst keinen internen State besitzen, etwa reine Anzeige-Texte ohne Formularfelder, ist der Index als key unbedenklich, weil sich die Zuordnung zwischen Index und logischer Identität nie ändert.

Ein Beispiel wäre eine feste Liste von Monatsnamen oder Navigationseinträgen, die zur Laufzeit konstant bleibt. In solchen Fällen ist der Aufwand, künstliche IDs einzuführen, unnötig, weil kein realistisches Szenario existiert, in dem die Positions-Index-Zuordnung bricht. Sobald aber auch nur die theoretische Möglichkeit einer Umsortierung oder Filterung besteht, sollte man von Anfang an eine stabile ID verwenden, um spätere, schwer auffindbare Bugs zu vermeiden.

7. Ein häufiger Folgefehler: UUID bei jedem Render neu generieren

Ein verwandter Fehler entsteht, wenn Entwickler versuchen, das Index-Problem zu vermeiden, aber die ID direkt im render-Aufruf mit crypto.randomUUID() neu generieren, statt sie einmalig beim Erzeugen der Daten festzulegen. Dadurch ändert sich der key-Wert bei jedem Render, React erkennt jedes Element als komplett neu und mountet die gesamte Liste bei jeder Aktualisierung neu, was jeglichen internen State verliert und die Performance verschlechtert.

Die korrekte Stelle für die ID-Generierung ist der Zeitpunkt, an dem das Datenobjekt erstellt wird, etwa beim Hinzufügen eines neuen Todo-Eintrags oder beim Laden der Daten von einer API, niemals während des Renderings selbst. Kommt die ID von einem Backend, ist ohnehin meist bereits eine stabile Datenbank-ID vorhanden, die sich direkt als key eignet.


// FALSCH: neue UUID bei jedem Render
function TodoList({ todos }) {
  return todos.map((todo) => (
    <TodoItem key={crypto.randomUUID()} todo={todo} />
  ));
}

// RICHTIG: ID einmalig beim Erzeugen des Datensatzes festlegen
function addTodo(title) {
  return { id: crypto.randomUUID(), title, done: false };
}

8. Debugging-Strategie: React DevTools und Symptome erkennen

Typische Symptome für falsche key-Werte sind Eingabefelder, die nach dem Löschen oder Sortieren eines Listenelements den falschen Inhalt zeigen, Checkbox- oder Toggle-Zustände, die an der falschen Zeile hängen bleiben, oder Animationen, die beim Umsortieren nicht wie erwartet greifen. React gibt zusätzlich eine Warnung in der Browser-Konsole aus, wenn Listenelemente ganz ohne key-Prop gerendert werden, allerdings nicht, wenn ein technisch vorhandener, aber ungeeigneter Index als key genutzt wird.

In den React DevTools lässt sich das Verhalten gezielt nachvollziehen, indem man ein Listenelement inspiziert, es im UI löscht oder umsortiert und beobachtet, ob die DOM-Knoten tatsächlich neu erzeugt oder nur verschoben werden. Bleibt ein DOM-Knoten trotz gelöschten logischen Elements bestehen, ist das ein klares Indiz für einen fehlerhaften key.

9. Praxis-Zusammenfassung für den täglichen Gebrauch

Die generelle Empfehlung lautet, standardmäßig eine stabile, inhaltlich verankerte ID zu verwenden, sobald Elemente einer Liste eigenen State besitzen können oder theoretisch umsortiert, gefiltert, eingefügt oder gelöscht werden könnten. Nur bei nachweislich statischen, state-losen Listen ist der Index eine legitime, einfache Alternative.

Die folgende Tabelle fasst die wichtigsten Szenarien zusammen und zeigt, welche key-Strategie jeweils angebracht ist, damit die Entscheidung im Alltag nicht jedes Mal neu durchdacht werden muss.

Szenario Index als key Stabile ID als key Empfehlung
Statische Liste ohne internen State unbedenklich auch möglich Index ausreichend
Liste mit Formularfeldern pro Element State-Recycling-Bugs korrekt immer stabile ID
Liste mit Löschen/Einfügen falsche Zuordnung korrekt immer stabile ID
Liste mit Sortier-Animation Animation greift nicht korrekt immer stabile ID

Mironsoft

React-Architektur, Performance und Magento-Frontend-Integration

React-Frontends, die schnell bleiben statt mit jedem Feature langsamer zu werden?

Wir prüfen bestehende React-Anwendungen auf unnötige Re-Renders, aufgeblähte Bundles und fragile State-Verwaltung und bauen daraus ein Frontend, das performant bleibt und sich sauber an Magento oder andere Backends anbindet.

Performance-Audit

Re-Renders, Bundle-Größe und Ladezeiten systematisch messen und beheben.

State-Architektur

Context, Zustand und Server State sauber trennen statt alles in einen Topf zu werfen.

Magento-Integration

GraphQL- oder REST-Anbindung an Magento robust und typsicher aufbauen.

10. Zusammenfassung

key-Prop: Das Wichtigste auf einen Blick

Kernproblem

Index als key koppelt Komponenten-Identität an Position statt an logische Identität.

Typischer Bug

State wie Eingabefeld-Inhalte bleibt nach Löschen/Sortieren am falschen Element hängen.

Korrekte Lösung

Stabile, inhaltlich verankerte ID beim Erzeugen des Datensatzes festlegen.

Erlaubte Ausnahme

Garantiert statische Listen ohne internen State pro Element.

11. FAQ: key-Prop: Das Wichtigste auf einen Blick

1Wofür verwendet React den key-Prop genau?
React nutzt den key-Wert, um Elemente in einer Liste über mehrere Renders hinweg als dieselbe logische Instanz zu identifizieren. Anhand dieser Zuordnung entscheidet React, ob internen State und DOM-Knoten beibehalten oder neu erzeugt werden.
2Warum funktioniert Index als key oft eine Weile problemlos?
Solange sich Reihenfolge und Zusammensetzung der Liste nicht ändern, stimmen Index und logische Identität zufällig überein. Der Fehler zeigt sich erst, sobald Elemente eingefügt, gelöscht oder umsortiert werden.
3Was genau passiert, wenn ich ein Listenelement mit Index-key lösche?
React verschiebt den internen State und DOM-Knoten fälschlicherweise auf das nächste Element an derselben Index-Position, statt ihn mit dem gelöschten Element zu entfernen. Eingabefeld-Inhalte oder Checkbox-Zustände landen dadurch am falschen Element.
4Ist Index als key immer ein Fehler?
Nein. Bei garantiert statischen Listen ohne internen State pro Element und ohne Sortier-, Filter- oder Löschmöglichkeit ist Index als key unbedenklich, weil sich die Zuordnung zwischen Index und Identität nie ändert.
5Woher bekomme ich eine stabile ID, wenn meine Daten keine hat?
Man generiert die ID einmalig beim Erzeugen des Datensatzes, etwa mit crypto.randomUUID(), und speichert sie als festes Feld im Objekt. Kommt die ID von einer API, ist meist bereits eine Datenbank-ID vorhanden, die direkt genutzt werden kann.
6Warum ist es falsch, die ID direkt im render-Aufruf zu generieren?
Weil sich der key-Wert dann bei jedem Render ändert. React erkennt jedes Element als komplett neu, mountet die gesamte Liste erneut und verliert dabei sämtlichen internen State, was Performance und Korrektheit gleichermaßen verschlechtert.
7Warnt React automatisch vor der Verwendung von Index als key?
React warnt nur, wenn Listenelemente gar keinen key-Prop besitzen, nicht wenn ein technisch vorhandener, aber ungeeigneter Index verwendet wird. Die Verantwortung liegt daher bei der Entwicklerin oder dem Entwickler.
8Wie erkenne ich einen key-Bug in den React DevTools?
Man inspiziert ein Listenelement, löst eine Löschung oder Umsortierung aus und prüft, ob der zugehörige DOM-Knoten tatsächlich entfernt oder nur der Inhalt eines bestehenden Knotens geändert wird. Bleibt ein Knoten trotz gelöschtem logischem Element bestehen, deutet das auf einen fehlerhaften key hin.
9Betrifft das key-Problem auch Animationsbibliotheken?
Ja. Bei Index als key erkennt eine Animationsbibliothek beim Umsortieren keine tatsächliche Bewegung eines Elements, weil React formal dieselbe Komponenten-Instanz an derselben Position beibehält. Sichtbare Übergangsanimationen bleiben dadurch aus.
10Muss ich in jeder Liste eine künstliche ID einführen, auch wenn sie sich nie ändert?
Nicht zwingend, aber es ist ratsam, sobald auch nur eine theoretische Möglichkeit künftiger Änderungen besteht. Der Aufwand für eine stabile ID ist gering im Vergleich zu den schwer auffindbaren Bugs, die durch nachträgliches Ändern einer als statisch angenommenen Liste entstehen können.