KoderKoder.ai
PreiseEnterpriseBildungFür Investoren
AnmeldenLoslegen

Produkt

PreiseEnterpriseFür Investoren

Ressourcen

Kontakt aufnehmenSupportBildungBlog

Rechtliches

DatenschutzrichtlinieNutzungsbedingungenSicherheitRichtlinie zur akzeptablen NutzungMissbrauch melden

Soziales

LinkedInTwitter
Koder.ai
Sprache

© 2026 Koder.ai. Alle Rechte vorbehalten.

Startseite›Blog›React-Komponenten sicher refactoren mit Claude Code
30. Dez. 2025·7 Min

React-Komponenten sicher refactoren mit Claude Code

Lerne, wie du React-Komponenten mit Claude Code sicher refactorst: Charakterisierungstests, kleine Schritte und State-Entwirrung, um Struktur zu verbessern ohne Verhalten zu ändern.

React-Komponenten sicher refactoren mit Claude Code

Warum React-Refactors in echtem Code riskant sind\n\nReact-Refactors wirken riskant, weil die meisten Komponenten keine kleinen, sauberen Bausteine sind. Sie sind lebende Ansammlungen aus UI, State, Effekten und „nur noch ein Prop“-Fixes. Wenn du Struktur änderst, veränderst du oft unbeabsichtigt Timing, Identität oder Datenfluss.\n\nEin Refactor ändert das Verhalten am häufigsten, wenn er aus Versehen:\n\n- State zurücksetzt, weil eine Komponenten-Grenze verschoben oder ein key geändert wurde.\n- Ändert, wann Effekte laufen, weil Abhängigkeiten verschoben oder Mount/Unmount geändert wurden.\n- Memoisierung kaputtmacht, sodass Handler und abgeleitete Werte bei jedem Render neu sind.\n- Event-Handling (Focus, Blur, Tastatur, Pointer) verschiebt, besonders nach Umhüllung oder Aufteilung des Markups.\n- Fetches oder Subscriptions dupliziert, weil Logik kopiert statt zentralisiert wurde.\n\nRefactors werden auch zu Rewrites, wenn „Aufräumen" mit „Verbesserungen" vermischt wird. Du beginnst mit dem Extrahieren einer Komponente, dann benennst du vieles um, dann „verbesserst" du die State-Form, dann ersetzt du einen Hook. Bald änderst du Logik und Layout zugleich. Ohne Schutzmechanismen ist schwer nachzuvollziehen, welche Änderung den Bug verursacht hat.\n\nEin sicherer Refactor gibt ein einfaches Versprechen: Nutzer sehen dasselbe Verhalten, und am Ende steht klarerer Code. Props, Events, Lade- und Fehlerzustände sowie Randfälle sollten gleich funktionieren. Wenn sich Verhalten ändert, muss es beabsichtigt, klein und klar ausgewiesen sein.\n\nWenn du React-Komponenten mit Claude Code (oder jedem Coding-Assistenten) refactorst, behandle ihn wie einen schnellen Pair-Programmer, nicht wie einen Autopiloten. Lass ihn die Risiken beschreiben, bevor du änderst, schlage einen Plan mit winzig kleinen Schritten vor und erkläre, wie überprüft wurde, dass das Verhalten gleich blieb. Validier danach selbst: starte die App, klick durch die merkwürdigen Pfade und verlass dich auf Tests, die festhalten, was die Komponente heute tut – nicht das, was du dir wünschst.\n\n## Ziel wählen und klares Refactor-Ziel setzen\n\nWähle eine einzelne Komponente, die dir aktiv Zeit kostet. Nicht die ganze Seite, nicht „die UI-Schicht“ und kein vages „Aufräumen“. Such eine Komponente aus, die schwer zu lesen, schwer zu ändern oder voller fragiler State- und Nebenwirkungslogik ist. Ein enges Ziel macht Vorschläge des Assistenten leichter prüfbar.\n\nFormuliere ein Ziel, das du in fünf Minuten prüfen kannst. Gute Ziele betreffen Struktur, nicht Ergebnis: „in kleinere Komponenten aufteilen“, „State leichter nachvollziehbar machen“ oder „testbar ohne halbe App zu mocken“. Vermeide Ziele wie „besser machen“ oder „Performance verbessern“, außer du hast eine Metrik und eine bekannte Engstelle.\n\nSetze Grenzen, bevor du den Editor öffnest. Die sichersten Refactors sind langweilig:\n\n- Keine visuellen Änderungen (gleiches Layout, gleicher Text, gleicher Abstand).\n- Keine neuen Features (auch nicht „während wir da sind, füge Sortierung hinzu“).\n- Gleiches externes Verhalten (Props rein, UI und Callbacks raus).\n- Eine Komponente nach der anderen (eine fertigstellen, bevor du die nächste beginnst).\n\nListe dann Abhängigkeiten auf, die beim Verschieben von Code heimlich das Verhalten brechen können: API-Aufrufe, Context-Provider, Routing-Parameter, Feature-Flags, Analytics-Events und geteilte globale Zustände.\n\nEin konkretes Beispiel: Du hast eine 600-Zeilen-OrdersTable, die Daten lädt, filtert, Auswahl verwaltet und ein Drawer mit Details zeigt. Ein klares Ziel könnte sein: „Row-Rendering und Drawer-UI in Komponenten extrahieren und Selection-State in einen Reducer verschieben, ohne UI-Änderungen.“ Dieses Ziel sagt, was „done“ bedeutet und was außer Scope ist.\n\n## Verhalten einfrieren, bevor du den Code anfasst\n\nBevor du refactorst, behandle die Komponente als Blackbox. Deine Aufgabe ist es, festzuhalten, was sie heute tut, nicht was du dir langfristig wünschst. Das verhindert, dass der Refactor in ein Redesign kippt.\n\nBeginne damit, das aktuelle Verhalten in einfacher Sprache aufzuschreiben: Bei diesen Eingaben zeigt die UI jenes Ergebnis. Schließe Props, URL-Parameter, Feature-Flags und alle Daten ein, die aus Context oder einem Store kommen. Wenn du Claude Code nutzt, füge einen kleinen, fokussierten Ausschnitt ein und lass ihn das Verhalten in präzisen Sätzen formulieren, die du später prüfen kannst.\n\nDecke die UI-Zustände ab, die Nutzer tatsächlich sehen. Eine Komponente kann auf dem Happy-Path gut aussehen, aber beim Laden, Leeren oder Fehler kaputtgehen.\n\nHalte auch implizite Regeln fest, die leicht übersehen werden und oft Refactors brechen:\n\n- Default-Auswahlen (ausgewählter Tab, Standard-Sortierspalte, initiale Filterwerte).\n- Formatierungsregeln (Datum, Währung, Abschneiden, Großschreibung).\n- Reihenfolge-Regeln (stabile Sortierung, Gruppierung, gepinnte Einträge).\n- Interaktionsregeln (was zurückgesetzt wird, wenn du einen Filter änderst, was Fokus behält).\n- Randfälle, auf die Nutzer angewiesen sind (leere Strings vs null, Null-Werte, partielle Daten).\n\nBeispiel: Du hast eine Nutzertabelle, die Ergebnisse lädt, Suche unterstützt und nach „Letzte Aktivität“ sortiert. Schreibe auf, was passiert, wenn die Suche leer ist, wenn die API eine leere Liste zurückgibt, wenn die API einen Fehler liefert und wenn zwei Nutzer die gleiche „Letzte Aktiv“-Zeit haben. Notiere kleine Details wie, ob Sortierung case-insensitive ist und ob die Tabelle die aktuelle Seite behält, wenn ein Filter geändert wird.\n\nWenn deine Notizen langweilig und spezifisch sind, bist du bereit.\n\n## Charakterisierungstests hinzufügen, die aktuelles Verhalten einfrieren\n\nCharakterisierungstests sind „so verhält es sich heute“-Tests. Sie beschreiben das aktuelle Verhalten, selbst wenn es merkwürdig, inkonsistent oder langfristig nicht ideal ist. Das klingt kontraintuitiv, aber es verhindert, dass ein Refactor stillschweigend in einen Rewrite gleitet.\n\nBeim Refactoren von React-Komponenten mit Claude Code sind diese Tests deine Sicherheitsgeländer. Das Tool kann Code umformen, aber du entscheidest, was unverändert bleiben muss.\n\nKonzentriere dich auf das, worauf Nutzer (und anderer Code) bauen:\n\n- Rendering: Was für wichtige Zustände gerendert wird (leer, laden, Fehler, normal).\n- Interaktionen: Klicks, Tippen, Tastaturnavigation, Auswahl, Pagination.\n- Abgeleitete Werte: Summen, gefilterte Counts, Formatierungsregeln, deaktivierte Zustände.\n- Nebeneffekte: Analytics-Calls, Draft-Speicherungen, URL-Updates, Fokus-Management.\n- Fehlerbehandlung: Was passiert, wenn eine Aktion fehlschlägt.\n\nUm Tests stabil zu halten, assertiere Ergebnisse, nicht Implementierung. Ziehe „Der Speichern-Button wird deaktiviert und eine Meldung erscheint“ vor gegenüber „setState wurde aufgerufen" oder „dieser Hook lief“. Wenn ein Test bricht, weil du eine Komponente umbenannt oder Hooks umsortiert hast, hat er Verhalten nicht geschützt.\n\nAsynchrones Verhalten ist ein Ort, an dem Refactors oft Timing ändern. Behandle es explizit: Warte, bis die UI sich stabilisiert hat, und assertiere dann. Wenn es Timer gibt (debounced search, verzögerte Toasts), verwende Fake-Timer und spule Zeit vor. Wenn es Netzwerkanfragen gibt, mocke fetch und assertiere, was der Nutzer nach Erfolg und nach Fehler sieht. Bei Suspense-ähnlichen Flows teste sowohl das Fallback als auch die aufgelöste Ansicht.\n\nBeispiel: Eine „Users“-Tabelle zeigt „Keine Ergebnisse“ erst, nachdem eine Suche abgeschlossen ist. Ein Charakterisierungstest sollte diese Sequenz festhalten: zuerst Lade-Indikator, dann entweder Zeilen oder die Leer-Meldung, unabhängig davon, wie du später die Komponente aufteilst.\n\n## Eine praktische Schritt-für-Schritt-Methode mit Claude Code\n\nDer Gewinn ist nicht „größere Änderungen schneller“. Der Gewinn ist, ein klares Bild davon zu haben, was die Komponente tut, und dann eine kleine Sache nach der anderen zu ändern, während das Verhalten stabil bleibt.\n\nBeginne damit, die Komponente einzufügen und um eine Plain-English-Zusammenfassung ihrer Verantwortlichkeiten zu bitten. Fordere Details: welche Daten sie zeigt, welche Nutzeraktionen sie handhabt und welche Nebeneffekte sie auslöst (Fetching, Timer, Subscriptions, Analytics). Das offenbart oft versteckte Aufgaben, die Refactors riskant machen.\n\nFrag dann nach einer Abhängigkeitskarte. Du willst ein Inventar aller Inputs und Outputs: Props, Context-Reads, Custom-Hooks, lokaler State, abgeleitete Werte, Effekte und modulweite Helfer. Eine nützliche Karte sagt auch, was sich sicher verschieben lässt (pure Berechnungen) und was „klebrig“ ist (Timing, DOM, Netzwerk).\n\nLass dir anschließend Extraktionskandidaten vorschlagen, mit einer strikten Regel: Trenne reine View-Teile von stateful Controller-Teilen. JSX-lastige Abschnitte, die nur Props brauchen, sind gute erste Extraktionen. Abschnitte, die Event-Handler, async-Calls und State-Updates mischen, sind es meist nicht.\n\nEin Workflow, der in echtem Code standhält:\n\n- Bestätige, dass die Zusammenfassung der Verantwortlichkeiten und die Abhängigkeitskarte zu dem passen, was du siehst.\n- Wähle einen Extraktionskandidaten, der größtenteils Präsentation ist, und verschiebe nur diesen.\n- Starte Charakterisierungstests neu und mache einen schnellen manuellen Durchlauf.\n- Nimm dir als Nächstes ein State-/Effect-Gewirr vor (nicht alles auf einmal) und teste erneut.\n- Wiederhole, bis die ursprüngliche Komponente wie ein kleiner Coordinator liest.\n\nCheckpoints sind wichtig. Bitte Claude Code um einen minimalen Plan, bei dem jeder Schritt committbar und revertierbar ist. Ein praktischer Checkpoint könnte sein: „Extrahiere \u003cTableHeader\u003e ohne Logikänderungen“, bevor du Sorting-State anfasst.\n\nKonkretes Beispiel: Wenn eine Komponente eine Kundentabelle rendert, Filter kontrolliert und Daten fetched, extrahiere zuerst das Table-Markup (Header, Zeilen, Empty State) in eine pure Komponente. Erst danach verschiebst du Filter-State oder den Fetch-Effekt. Diese Reihenfolge verhindert, dass Bugs mit dem JSX mitwandern.\n\n## Komponenten extrahieren, ohne Bugs zu verschieben\n\nBeim Aufteilen einer großen Komponente besteht das Risiko nicht im Verschieben des JSX, sondern darin, unbeabsichtigt Datenfluss, Timing oder Event-Verkabelung zu ändern. Betrachte Extraktion zuerst als Copy-and-Wire-Übung, später als Cleanup-Übung.\n\nBeginne damit, Grenzen zu finden, die bereits in der UI existieren, nicht in deiner Dateistruktur. Such nach Teilen, die du als eigenes „Ding" beschreiben könntest: ein Header mit Aktionen, eine Filterleiste, eine Ergebnisliste, ein Footer mit Pagination.\n\nEin sicherer erster Schritt ist das Extrahieren reiner Präsentationskomponenten: Props rein, JSX raus. Halte sie absichtlich langweilig. Kein neuer State, keine Effekte, keine neuen API-Aufrufe. Wenn die Originalkomponente einen Klick-Handler hatte, der drei Dinge tut, behalte den Handler im Parent und reiche ihn runter.\n\nGute sichere Grenzen sind typischerweise Header-Bereich, Liste und Row-Item, Filter (nur Inputs), Footer-Steuerungen (Pagination, Totals, Bulk-Aktionen) und Dialoge (Open/Close und Callbacks reinreichen).\n\nNamen sind wichtiger, als viele denken. Wähle spezifische Namen wie UsersTableHeader oder InvoiceRowActions. Vermeide Sammelbezeichnungen wie „Utils“ oder „HelperComponent“, weil sie Verantwortlichkeiten verschleiern und dazu verleiten, Belange zu vermischen.\n\nFühre erst dann Container-Komponenten ein, wenn es wirklich nötig ist: ein UI-Block, der State oder Effekte besitzen muss, um kohärent zu bleiben. Selbst dann sollte er eng sein. Ein guter Container hat genau einen Zweck (z. B. „Filter-State“) und reicht den Rest als Props durch.\n\n## State und Effekte entwirren in kleinen, sicheren Schritten\n\nUnordentliche Komponenten mischen meist drei Datenarten: echter UI-State (was der Nutzer geändert hat), abgeleitete Daten (was du berechnen kannst) und Server-State (Daten aus dem Netzwerk). Wenn du alles als lokalen State behandelst, werden Refactors riskant, weil du unbeabsichtigt änderst, wann Dinge aktualisiert werden.\n\nBeginne damit, jede Datenstelle zu labeln. Frag: Bearbeitet der Nutzer das, oder kann ich es aus Props, State und gecachten Daten berechnen? Frag auch: Wird dieser Wert hier besessen, oder wird er nur durchgereicht?\n\n### State von abgeleiteten Werten trennen\n\nAbgeleitete Werte sollten nicht in useState leben. Verschiebe sie in eine kleine Funktion oder einen memoisierten Selektor, wenn es teuer ist. Das reduziert State-Updates und macht Verhalten vorhersehbarer.\n\nEin sicheres Muster:\n\n- Halte nur vom Nutzer bearbeitete Werte in useState.\n- Berechne view-only Werte aus diesen Eingaben.\n- Reiche berechnete Werte runter, nicht deren Setter, es sei denn, ein Kind bearbeitet sie wirklich.\n- Wenn Performance wichtig ist, umschließe teure Berechnungen mit useMemo.\n\n### Effekte langweilig und spezifisch machen\n\nEffekte brechen Verhalten, wenn sie zu viel tun oder auf die falschen Abhängigkeiten reagieren. Ziel ist: ein Effekt pro Zweck – einer fürs Syncen zu localStorage, einer fürs Fetching, einer für Subscriptions. Wenn ein Effekt viele Werte liest, versteckt er meist zusätzliche Verantwortlichkeiten.\n\nWenn du Claude Code nutzt, bitte um eine winzige Änderung: Splitte einen Effekt in zwei oder verschiebe eine Verantwortung in einen Helfer. Führe dann Charakterisierungstests nach jedem Schritt aus.\n\nAchte auf Prop-Drilling. Den mit Context zu ersetzen hilft nur, wenn es wiederholte Verkabelung entfernt und Ownership klarer macht. Ein gutes Zeichen ist, wenn Context nach einem App-weiten Konzept klingt (aktueller Nutzer, Theme, Feature-Flags) und nicht wie ein Workaround für einen Komponentenbaum.\n\nBeispiel: Eine Table-Komponente speichert sowohl rows als auch filteredRows im State. Behalte rows im State, berechne filteredRows aus rows plus query und halte die Filterlogik in einer reinen Funktion, damit sie leicht testbar und schwer zu brechen ist.\n\n## Checkpoints nutzen, um schnell revertieren zu können\n\nRefactors gehen meistens schief, wenn du zu viel änderst, bevor du es bemerkst. Die Lösung ist simpel: arbeite in winzigen Checkpoints und behandle jeden wie ein Mini-Release. Selbst wenn du in einem Branch arbeitest, halte deine Änderungen PR-groß, damit du sehen kannst, was kaputtging und warum.\n\nNach jedem sinnvollen Schritt (Komponente extrahiert, State-Fluss geändert) halte an und beweise, dass du das Verhalten nicht geändert hast. Dieser Beweis kann automatisiert (Tests) und manuell (schnelle Checks im Browser) erfolgen. Ziel ist nicht Perfektion, sondern schnelle Fehlererkennung.\n\nEine praktische Checkpoint-Schleife:\n\n- Mach eine kleine Änderung (eine Extraktion, einen State-Move, ein Effect-Cleanup).\n- Führe die Test-Suite aus oder zumindest die Charakterisierungstests für den Bereich.\n- Mach einen schnellen manuellen Spot-Check der wichtigsten Nutzerpfade.\n- Speichere einen Rollback-Punkt (git commit oder Plattform-Snapshot).\n\nWenn du eine Plattform wie Koder.ai benutzt, können Snapshots und Rollback wie Sicherheitsgeländer wirken, während du iterierst. Du willst trotzdem normale Commits, aber Snapshots helfen beim Vergleich einer „bekannten guten" Version mit deiner aktuellen, oder wenn ein Experiment danebengeht.\n\nFühre ein einfaches Verhaltens-Logbuch währenddessen. Es ist nur eine kurze Notiz dessen, was du verifiziert hast, und verhindert, dass du dieselben Dinge immer wieder prüfst.\n\nBeispiel:\n\n- Table-Sortierung: sortiert noch nach derselben Spalte und Icon zeigt Zustand korrekt.\n- Row-Selection: Auswahlanzahl aktualisiert sich, Bulk-Aktionen aktivieren korrekt.\n- Loading und Error: Spinner und Retry-Button erscheinen in denselben Fällen.\n\nWenn etwas kaputtgeht, sagt dir das Log, was du erneut prüfen musst, und deine Checkpoints machen das Revertieren günstig.\n\n## Häufige Fallen, die Verhalten während Refactors brechen\n\nDie meisten Refactors scheitern an kleinen, langweiligen Dingen. Die UI funktioniert größtenteils, aber eine Abstandsregel verschwindet, ein Klick-Handler feuert doppelt, oder eine Liste verliert Fokus beim Tippen. Assistenten können das verschlimmern, weil der Code sauberer aussieht, während Verhalten driftet.\n\nEine häufige Ursache ist Strukturänderung. Du extrahierst eine Komponente, wickelst Dinge in ein zusätzliches \u003cdiv\u003e oder tauschst ein \u003cbutton\u003e gegen ein klickbares \u003cdiv\u003e. CSS-Selektoren, Layout, Tastaturnavigation und Test-Queries können sich ändern, ohne dass es jemand merkt.\n\nDie Fallen, die Verhalten am häufigsten brechen:\n\n- DOM-Änderungen, die harmlos wirken: Extra-Wrapper, andere Elementtypen oder verschobene Attribute können CSS und Tests brechen. Behalte dieselben Tags und data-Attribute, bis du sie bewusst ändern willst.\n- Referentielle Gleichheit versehentlich brechen: Inline neu erstellte Objekte/Funktionen ({} oder () => {}) können Extra-Rerenders und Reset von Child-State auslösen. Achte auf Props, die früher stabil waren.\n- Hook-Dependency-Fehler: Logik in useEffect, useMemo oder useCallback zu verschieben kann stale Werte oder Loops erzeugen, wenn Abhängigkeiten falsch sind. Wenn ein Effekt früher „on click“ lief, verwandle ihn nicht in etwas, das „whenever anything changes“ läuft.\n- Verhalten ohne Erlaubnis upgraden: Edge-Cases „fixen“, Sortierregeln ändern oder Validierung verbessern ist Produktarbeit. Match das heutige Verhalten zuerst, auch wenn es merkwürdig ist.\n\nKonkretes Beispiel: Du teilst eine Table-Komponente auf und änderst die Row-Keys von einer ID zu einem Array-Index. Das sieht erst in Ordnung aus, kann aber Selection-State brechen, wenn Reihen neu geordnet werden. Betrachte „sauber" als Bonus. Behandle „gleiches Verhalten" als Requirement.\n\n## Schnelle Checkliste, bevor du abschließt\n\nBevor du merge, willst du Beweise, dass der Refactor das Verhalten beibehalten hat. Das einfachste Signal ist langweilig: alles funktioniert weiterhin, ohne dass du Tests „reparieren" musst.\n\nMach diesen schnellen Pass nach der letzten kleinen Änderung:\n\n- Alte Tests laufen ohne Änderungen, und deine neuen Charakterisierungstests bestehen ebenfalls (keine aktualisierten Snapshots, keine geänderten Assertions).\n- Die UI zeigt weiterhin dieselben sichtbaren Zustände: Loading, Empty, Error, Success, und sie treten unter denselben Bedingungen auf.\n- Öffentliche Props und Callback-Verträge blieben stabil: gleiche Namen, gleiche Argumentformen, gleiche Timing-Eigenschaften (z. B. feuert onChange weiterhin bei Nutzer-Input, nicht beim Mount).\n- Fokus- und Tastaturverhalten fühlt sich gleich an: Tab-Reihenfolge, Enter- und Escape-Handling und wohin der Fokus nach Aktionen wie Speichern, Schließen oder Pagination springt.\n- Analytics und Nebeneffekte passieren weiterhin einmal, zum selben Zeitpunkt wie vorher (z. B. ein „Viewed“-Event pro Screen-Load, nicht pro Re-Render).\n\nEin schneller Sanity-Check: Öffne die Komponente und mache einen merkwürdigen Ablauf, z. B. Fehler auslösen, erneut versuchen, dann Filter zurücksetzen. Refactors brechen oft Übergänge, selbst wenn der Hauptpfad funktioniert.\n\nWenn etwas fehlschlägt, revertiere die letzte Änderung und mache sie in einem kleineren Schritt neu. Das ist meist schneller als ein großes Diff zu debuggen.\n\n## Ein realistisches Beispiel: Eine unordentliche Table-Komponente aufteilen\n\nStell dir eine ProductTable vor, die alles macht: Daten laden, Filter verwalten, Pagination steuern, ein Bestätigungsdialog zum Löschen öffnen und Row-Aktionen wie Edit, Duplicate und Archive handhaben. Sie begann klein und wuchs zu einer 900-Zeilen-Datei.\n\nDie Symptome sind vertraut: State ist über mehrere useState verteilt, ein paar useEffects laufen in einer bestimmten Reihenfolge, und eine „harmlose" Änderung bricht Pagination nur, wenn ein Filter aktiv ist. Leute fassen sie nicht mehr an, weil sie unberechenbar wirkt.\n\nBevor du Struktur änderst, sperre das Verhalten mit einigen Charakterisierungstests. Konzentriere dich auf Nutzeraktionen, nicht internen State:\n\n- Filter anwenden aktualisiert sichtbare Zeilen und setzt auf Seite 1 zurück.\n- Pagination behält Filter und zeigt korrekte Seitenanzahl.\n- Klick auf „Archive" deaktiviert die Zeile, während die Anforderung läuft.\n- Leerer Zustand zeigt, wenn keine Ergebnisse zu den Filtern passen.\n- Ladezustand flackert nicht „Keine Ergebnisse" auf.\n\nDann kannst du in kleinen Commits refactoren. Ein sauberer Extraktionsplan könnte so aussehen: FilterBar rendert Controls und emittiert Filter-Änderungen; TableView rendert Zeilen und Pagination; RowActions besitzt das Action-Menü und die Confirm-Dialog-UI; und ein useProductTable Hook besitzt die unordentliche Logik (Query-Params, abgeleiteter State und Nebeneffekte).\n\nDie Reihenfolge ist entscheidend. Extrahiere zuerst dumme UI (TableView, FilterBar) und reiche Props unverändert durch. Heb dir den riskanten Teil für zuletzt auf: State und Effekte in useProductTable verschieben. Halte alte Prop-Namen und Event-Formen, damit Tests weiterlaufen. Wenn ein Test fehlschlägt, hast du eine Verhaltensänderung gefunden, keinen Stilbruch.\n\n## Nächste Schritte: Diese Methode wiederholbar machen\n\nWenn du willst, dass das Refactoring mit Claude Code jedes Mal sicher ist, mach das Vorgehen zu einer kleinen Vorlage, die du wiederverwenden kannst. Ziel ist nicht mehr Prozess, sondern weniger Überraschungen.\n\n### Eine einfache Refactor-Vorlage behalten\n\nSchreibe ein kurzes Playbook, dem du bei jeder Komponente folgen kannst, auch wenn du müde oder gehetzt bist:\n\n- Formuliere das Ziel in einem Satz (was sich verbessert, was nicht geändert werden darf).\n- Halte aktuelles Verhalten mit Charakterisierungstests fest (inklusive ungewöhnlicher Randfälle).\n- Mach eine kleine Änderung (extrahieren, umbenennen, State verschieben, Effekte isolieren).\n- Führe Tests aus und mache einen schnellen manuellen UI-Check.\n- Speichere einen Checkpoint, zu dem du zurückkehren kannst, falls nötig.\n\nSpeichere das als Snippet in deinen Notizen oder im Repo, damit der nächste Refactor mit denselben Sicherheitsregeln beginnt.\n\n### Entscheide, was nach dem Verhalten-Sichern folgt\n\nWenn die Komponente stabil und leichter zu lesen ist, wähle den nächsten Schritt nach Nutzer-Relevanz. Eine übliche Reihenfolge ist: Accessibility zuerst (Labels, Fokus, Tastatur), dann Performance (Memoization, teure Renders), dann Cleanup (Types, Naming, toter Code). Mische nicht alle drei in einem PR.\n\nWenn du einen vibe-coding Workflow wie Koder.ai (koder.ai) nutzt, kann der Planungsmodus helfen, Schritte zu skizzieren, bevor du Code anfasst, und Snapshots/Rollback dienen als Checkpoints beim Iterieren. Am Ende erleichtert es der Export des Source-Codes, das finale Diff zu reviewen und eine saubere Historie zu behalten.\n\n### Weiß, wann du aufhören und ausliefern solltest\n\nHör auf zu refactoren, wenn Tests das Verhalten abdecken, vor dem du Angst hattest, die nächste Änderung ein Feature wäre oder du den Drang hast, im gleichen PR „perfekt" zu machen. Wenn das Aufteilen eines großen Formulars den verknoteten State entfernt hat und Tests Validierung und Submit abdecken, merge den Refactor. Lege verbleibende Ideen als kurze Backlog-Items ab.

FAQ

Warum brechen React-Refactors Dinge, obwohl die UI gleich aussieht?

React-Refactors verändern oft unbemerkt Identität und Timing. Häufige Verhaltensprobleme sind:\n\n- Zustand wird zurückgesetzt, weil eine Komponenten-Grenze oder ein key geändert wurde.\n- Effekte laufen zu anderen Zeitpunkten, weil Mount/Unmount oder Abhängigkeiten sich geändert haben.\n- Ereignisbehandlung verschiebt sich (Focus/Blur/Tastatur) nachdem Markup umwickelt oder aufgeteilt wurde.\n\nGehe davon aus, dass eine Strukturänderung ein Verhaltensänderung sein kann, bis Tests das Gegenteil beweisen.

Was ist ein gutes Refactor-Ziel für eine unordentliche React-Komponente?

Formuliere ein enges, prüfbares Ziel, das sich auf Struktur konzentriert, nicht auf allgemeine „Verbesserungen“. Gute Ziele lauten z. B.:\n\n- „Header, Zeilen und Drawer in Komponenten extrahieren ohne UI-Änderungen.“\n- „Selection-State in einen Reducer verschieben ohne Events oder Props zu ändern.“\n\nVermeide vage Ziele wie „besser machen“, es sei denn, du hast eine Messgröße und eine bekannte Engstelle.

Wie „friere“ ich das aktuelle Verhalten ein, bevor ich refactore?

Behandle die Komponente als Blackbox und schreibe auf, was Nutzer beobachten können:\n\n- Loading/Empty/Error/Success-Zustände und wann jeder erscheint\n- Defaults (ausgewählter Tab, Sortierspalte, Initialfilter)\n- Interaktionsregeln (was zurückgesetzt wird, wenn Filter sich ändern, was Fokus behält)\n- Formatierungs- und Sortierregeln (Datum, Währung, stabile Sortierung)\n\nWenn deine Notizen langweilig und spezifisch sind, sind sie nützlich.

Welche Tests geben mir die meiste Sicherheit während eines React-Refactors?

Füge Charakterisierungstests hinzu, die beschreiben, was die Komponente heute tut – auch wenn es merkwürdig ist.\n\nPraktische Ziele:\n\n- Was für Schlüsselzustände gerendert wird (Loading, Empty, Error)\n- Nutzerinteraktionen (Tippen, Pagination, Auswahl)\n- Nebeneffekte (Analytics, URL-Updates, Subscriptions)\n- Asynchrone Sequenzen (erst Spinner, dann Zeilen/Leer/Fehler)\n\nAssertiere Ergebnisse im UI, nicht interne Hook-Aufrufe.

Wie nutze ich Claude Code (oder einen Assistenten), ohne die Kontrolle über das Verhalten zu verlieren?

Lass es wie einen sorgfältigen Pair-Programmer arbeiten:\n\n- Zuerst: Verantwortlichkeiten zusammenfassen und Inputs/Outputs (Props, Context, Effekte) auflisten.\n- Dann: Einen kleinen Plan mit commit-großen Schritten vorschlagen lassen.\n- Für jeden Schritt: ausführen, was kaputtgehen könnte (State-Reset, Effekt-Timing, Event-Wiring).\n\nAkzeptiere keinen großen „Rewrite“-Diff; bestehe auf inkrementellen Änderungen, die du verifizieren kannst.

Was ist die sicherste Reihenfolge, um eine große Komponente aufzuteilen?

Beginne mit der Extraktion reiner Präsentationsteile:\n\n- Props rein, JSX raus\n- Kein eigener State, keine Effekte, kein Fetching\n- Handler im Parent behalten und runterreichen\n\nZuerst copy-and-wire; später aufräumen. Erst wenn die UI sicher geteilt ist, die State-/Effekt-Teile in kleinen Schritten angehen.

Warum ist das Ändern von List-Keys während eines Refactors so gefährlich?

Verwende stabile Keys, die auf echter Identität beruhen (z. B. eine ID), nicht Array-Indizes.\n\nIndex-Keys scheinen oft zu funktionieren, bis du sortierst, filterst, einfügst oder löschst – dann wiederverwendet React die falschen Instanzen und du bekommst Fehler wie:\n\n- Falsche Zeile bleibt ausgewählt\n- Inputs verlieren Fokus oder tauschen Werte\n- Lokaler Zeilen-Status hängt am falschen Element\n\nWenn dein Refactor Keys ändert, behandle das als hohes Risiko und teste Reorder-Fälle.

Wie entwirre ich State und abgeleitete Daten ohne Verhalten zu ändern?

Lagere abgeleitete Werte aus useState aus, wenn du sie aus Props, State und Fetch-Daten berechnen kannst.\n\nSicherer Ansatz:\n\n- Nur vom Benutzer bearbeitete oder extern kontrollierte Werte in State halten\n- Abgeleitete Daten (filteredRows) aus rows + query berechnen\n- useMemo nur bei teuren Berechnungen verwenden\n\nDas reduziert unerwartete Updates und macht Komponenten leichter verständlich.

Was ist eine gute Checkpoint-Schleife, damit Refactors nicht zu Rewrites werden?

Nutze Checkpoints, damit jeder Schritt leicht revertierbar ist:\n\n- Eine kleine Änderung machen (eine Extraktion oder ein Effect-Split)\n- Relevante Charakterisierungstests ausführen\n- Schnell einen „komischen Pfad“-Check im Browser machen (Fehler → Retry → Filter löschen)\n- Ein Rollback-Punkt speichern (git commit oder Plattform-Snapshot)\n\nWenn du Koder.ai nutzt, ergänzen Snapshots normale Commits beim Experimentieren.

Woran erkenne ich, wann ich mit dem Refactoring aufhören und ausliefern sollte?

Hör auf, wenn Verhalten abgesichert ist und der Code leichter zu ändern ist. Gute Abbruchsignale:\n\n- Tests decken die Pfade ab, die du nicht zu brechen wagtest\n- Weitere Änderungen würden neue Features oder Produkt-Entscheidungen hinzufügen\n- Du hast den Drang, in demselben PR noch Namen, Typen und Architektur zu perfektionieren\n\nMerge den Refactor und leg offene Verbesserungen (Accessibility, Performance, Cleanup) in eine kurze Nachbearbeitungsliste.

Inhalt
Warum React-Refactors in echtem Code riskant sind\n\nReact-Refactors wirken riskant, weil die meisten Komponenten keine kleinen, sauberen Bausteine sind. Sie sind lebende Ansammlungen aus UI, State, Effekten und „nur noch ein Prop“-Fixes. Wenn du Struktur änderst, veränderst du oft unbeabsichtigt Timing, Identität oder Datenfluss.\n\nEin Refactor ändert das Verhalten am häufigsten, wenn er aus Versehen:\n\n- State zurücksetzt, weil eine Komponenten-Grenze verschoben oder ein key geändert wurde.\n- Ändert, wann Effekte laufen, weil Abhängigkeiten verschoben oder Mount/Unmount geändert wurden.\n- Memoisierung kaputtmacht, sodass Handler und abgeleitete Werte bei jedem Render neu sind.\n- Event-Handling (Focus, Blur, Tastatur, Pointer) verschiebt, besonders nach Umhüllung oder Aufteilung des Markups.\n- Fetches oder Subscriptions dupliziert, weil Logik kopiert statt zentralisiert wurde.\n\nRefactors werden auch zu Rewrites, wenn „Aufräumen" mit „Verbesserungen" vermischt wird. Du beginnst mit dem Extrahieren einer Komponente, dann benennst du vieles um, dann „verbesserst" du die State-Form, dann ersetzt du einen Hook. Bald änderst du Logik und Layout zugleich. Ohne Schutzmechanismen ist schwer nachzuvollziehen, welche Änderung den Bug verursacht hat.\n\nEin sicherer Refactor gibt ein einfaches Versprechen: Nutzer sehen dasselbe Verhalten, und am Ende steht klarerer Code. Props, Events, Lade- und Fehlerzustände sowie Randfälle sollten gleich funktionieren. Wenn sich Verhalten ändert, muss es beabsichtigt, klein und klar ausgewiesen sein.\n\nWenn du React-Komponenten mit Claude Code (oder jedem Coding-Assistenten) refactorst, behandle ihn wie einen schnellen Pair-Programmer, nicht wie einen Autopiloten. Lass ihn die Risiken beschreiben, bevor du änderst, schlage einen Plan mit winzig kleinen Schritten vor und erkläre, wie überprüft wurde, dass das Verhalten gleich blieb. Validier danach selbst: starte die App, klick durch die merkwürdigen Pfade und verlass dich auf Tests, die festhalten, was die Komponente heute tut – nicht das, was du dir wünschst.\n\n## Ziel wählen und klares Refactor-Ziel setzen\n\nWähle eine einzelne Komponente, die dir aktiv Zeit kostet. Nicht die ganze Seite, nicht „die UI-Schicht“ und kein vages „Aufräumen“. Such eine Komponente aus, die schwer zu lesen, schwer zu ändern oder voller fragiler State- und Nebenwirkungslogik ist. Ein enges Ziel macht Vorschläge des Assistenten leichter prüfbar.\n\nFormuliere ein Ziel, das du in fünf Minuten prüfen kannst. Gute Ziele betreffen Struktur, nicht Ergebnis: „in kleinere Komponenten aufteilen“, „State leichter nachvollziehbar machen“ oder „testbar ohne halbe App zu mocken“. Vermeide Ziele wie „besser machen“ oder „Performance verbessern“, außer du hast eine Metrik und eine bekannte Engstelle.\n\nSetze Grenzen, bevor du den Editor öffnest. Die sichersten Refactors sind langweilig:\n\n- Keine visuellen Änderungen (gleiches Layout, gleicher Text, gleicher Abstand).\n- Keine neuen Features (auch nicht „während wir da sind, füge Sortierung hinzu“).\n- Gleiches externes Verhalten (Props rein, UI und Callbacks raus).\n- Eine Komponente nach der anderen (eine fertigstellen, bevor du die nächste beginnst).\n\nListe dann Abhängigkeiten auf, die beim Verschieben von Code heimlich das Verhalten brechen können: API-Aufrufe, Context-Provider, Routing-Parameter, Feature-Flags, Analytics-Events und geteilte globale Zustände.\n\nEin konkretes Beispiel: Du hast eine 600-Zeilen-`OrdersTable`, die Daten lädt, filtert, Auswahl verwaltet und ein Drawer mit Details zeigt. Ein klares Ziel könnte sein: „Row-Rendering und Drawer-UI in Komponenten extrahieren und Selection-State in einen Reducer verschieben, ohne UI-Änderungen.“ Dieses Ziel sagt, was „done“ bedeutet und was außer Scope ist.\n\n## Verhalten einfrieren, bevor du den Code anfasst\n\nBevor du refactorst, behandle die Komponente als Blackbox. Deine Aufgabe ist es, festzuhalten, was sie heute tut, nicht was du dir langfristig wünschst. Das verhindert, dass der Refactor in ein Redesign kippt.\n\nBeginne damit, das aktuelle Verhalten in einfacher Sprache aufzuschreiben: Bei diesen Eingaben zeigt die UI jenes Ergebnis. Schließe Props, URL-Parameter, Feature-Flags und alle Daten ein, die aus Context oder einem Store kommen. Wenn du Claude Code nutzt, füge einen kleinen, fokussierten Ausschnitt ein und lass ihn das Verhalten in präzisen Sätzen formulieren, die du später prüfen kannst.\n\nDecke die UI-Zustände ab, die Nutzer tatsächlich sehen. Eine Komponente kann auf dem Happy-Path gut aussehen, aber beim Laden, Leeren oder Fehler kaputtgehen.\n\nHalte auch implizite Regeln fest, die leicht übersehen werden und oft Refactors brechen:\n\n- Default-Auswahlen (ausgewählter Tab, Standard-Sortierspalte, initiale Filterwerte).\n- Formatierungsregeln (Datum, Währung, Abschneiden, Großschreibung).\n- Reihenfolge-Regeln (stabile Sortierung, Gruppierung, gepinnte Einträge).\n- Interaktionsregeln (was zurückgesetzt wird, wenn du einen Filter änderst, was Fokus behält).\n- Randfälle, auf die Nutzer angewiesen sind (leere Strings vs null, Null-Werte, partielle Daten).\n\nBeispiel: Du hast eine Nutzertabelle, die Ergebnisse lädt, Suche unterstützt und nach „Letzte Aktivität“ sortiert. Schreibe auf, was passiert, wenn die Suche leer ist, wenn die API eine leere Liste zurückgibt, wenn die API einen Fehler liefert und wenn zwei Nutzer die gleiche „Letzte Aktiv“-Zeit haben. Notiere kleine Details wie, ob Sortierung case-insensitive ist und ob die Tabelle die aktuelle Seite behält, wenn ein Filter geändert wird.\n\nWenn deine Notizen langweilig und spezifisch sind, bist du bereit.\n\n## Charakterisierungstests hinzufügen, die aktuelles Verhalten einfrieren\n\nCharakterisierungstests sind „so verhält es sich heute“-Tests. Sie beschreiben das aktuelle Verhalten, selbst wenn es merkwürdig, inkonsistent oder langfristig nicht ideal ist. Das klingt kontraintuitiv, aber es verhindert, dass ein Refactor stillschweigend in einen Rewrite gleitet.\n\nBeim Refactoren von React-Komponenten mit Claude Code sind diese Tests deine Sicherheitsgeländer. Das Tool kann Code umformen, aber du entscheidest, was unverändert bleiben muss.\n\nKonzentriere dich auf das, worauf Nutzer (und anderer Code) bauen:\n\n- Rendering: Was für wichtige Zustände gerendert wird (leer, laden, Fehler, normal).\n- Interaktionen: Klicks, Tippen, Tastaturnavigation, Auswahl, Pagination.\n- Abgeleitete Werte: Summen, gefilterte Counts, Formatierungsregeln, deaktivierte Zustände.\n- Nebeneffekte: Analytics-Calls, Draft-Speicherungen, URL-Updates, Fokus-Management.\n- Fehlerbehandlung: Was passiert, wenn eine Aktion fehlschlägt.\n\nUm Tests stabil zu halten, assertiere Ergebnisse, nicht Implementierung. Ziehe „Der Speichern-Button wird deaktiviert und eine Meldung erscheint“ vor gegenüber „setState wurde aufgerufen" oder „dieser Hook lief“. Wenn ein Test bricht, weil du eine Komponente umbenannt oder Hooks umsortiert hast, hat er Verhalten nicht geschützt.\n\nAsynchrones Verhalten ist ein Ort, an dem Refactors oft Timing ändern. Behandle es explizit: Warte, bis die UI sich stabilisiert hat, und assertiere dann. Wenn es Timer gibt (debounced search, verzögerte Toasts), verwende Fake-Timer und spule Zeit vor. Wenn es Netzwerkanfragen gibt, mocke fetch und assertiere, was der Nutzer nach Erfolg und nach Fehler sieht. Bei Suspense-ähnlichen Flows teste sowohl das Fallback als auch die aufgelöste Ansicht.\n\nBeispiel: Eine „Users“-Tabelle zeigt „Keine Ergebnisse“ erst, nachdem eine Suche abgeschlossen ist. Ein Charakterisierungstest sollte diese Sequenz festhalten: zuerst Lade-Indikator, dann entweder Zeilen oder die Leer-Meldung, unabhängig davon, wie du später die Komponente aufteilst.\n\n## Eine praktische Schritt-für-Schritt-Methode mit Claude Code\n\nDer Gewinn ist nicht „größere Änderungen schneller“. Der Gewinn ist, ein klares Bild davon zu haben, was die Komponente tut, und dann eine kleine Sache nach der anderen zu ändern, während das Verhalten stabil bleibt.\n\nBeginne damit, die Komponente einzufügen und um eine Plain-English-Zusammenfassung ihrer Verantwortlichkeiten zu bitten. Fordere Details: welche Daten sie zeigt, welche Nutzeraktionen sie handhabt und welche Nebeneffekte sie auslöst (Fetching, Timer, Subscriptions, Analytics). Das offenbart oft versteckte Aufgaben, die Refactors riskant machen.\n\nFrag dann nach einer Abhängigkeitskarte. Du willst ein Inventar aller Inputs und Outputs: Props, Context-Reads, Custom-Hooks, lokaler State, abgeleitete Werte, Effekte und modulweite Helfer. Eine nützliche Karte sagt auch, was sich sicher verschieben lässt (pure Berechnungen) und was „klebrig“ ist (Timing, DOM, Netzwerk).\n\nLass dir anschließend Extraktionskandidaten vorschlagen, mit einer strikten Regel: Trenne reine View-Teile von stateful Controller-Teilen. JSX-lastige Abschnitte, die nur Props brauchen, sind gute erste Extraktionen. Abschnitte, die Event-Handler, async-Calls und State-Updates mischen, sind es meist nicht.\n\nEin Workflow, der in echtem Code standhält:\n\n- Bestätige, dass die Zusammenfassung der Verantwortlichkeiten und die Abhängigkeitskarte zu dem passen, was du siehst.\n- Wähle einen Extraktionskandidaten, der größtenteils Präsentation ist, und verschiebe nur diesen.\n- Starte Charakterisierungstests neu und mache einen schnellen manuellen Durchlauf.\n- Nimm dir als Nächstes ein State-/Effect-Gewirr vor (nicht alles auf einmal) und teste erneut.\n- Wiederhole, bis die ursprüngliche Komponente wie ein kleiner Coordinator liest.\n\nCheckpoints sind wichtig. Bitte Claude Code um einen minimalen Plan, bei dem jeder Schritt committbar und revertierbar ist. Ein praktischer Checkpoint könnte sein: „Extrahiere `\u003cTableHeader\u003e` ohne Logikänderungen“, bevor du Sorting-State anfasst.\n\nKonkretes Beispiel: Wenn eine Komponente eine Kundentabelle rendert, Filter kontrolliert und Daten fetched, extrahiere zuerst das Table-Markup (Header, Zeilen, Empty State) in eine pure Komponente. Erst danach verschiebst du Filter-State oder den Fetch-Effekt. Diese Reihenfolge verhindert, dass Bugs mit dem JSX mitwandern.\n\n## Komponenten extrahieren, ohne Bugs zu verschieben\n\nBeim Aufteilen einer großen Komponente besteht das Risiko nicht im Verschieben des JSX, sondern darin, unbeabsichtigt Datenfluss, Timing oder Event-Verkabelung zu ändern. Betrachte Extraktion zuerst als Copy-and-Wire-Übung, später als Cleanup-Übung.\n\nBeginne damit, Grenzen zu finden, die bereits in der UI existieren, nicht in deiner Dateistruktur. Such nach Teilen, die du als eigenes „Ding" beschreiben könntest: ein Header mit Aktionen, eine Filterleiste, eine Ergebnisliste, ein Footer mit Pagination.\n\nEin sicherer erster Schritt ist das Extrahieren reiner Präsentationskomponenten: Props rein, JSX raus. Halte sie absichtlich langweilig. Kein neuer State, keine Effekte, keine neuen API-Aufrufe. Wenn die Originalkomponente einen Klick-Handler hatte, der drei Dinge tut, behalte den Handler im Parent und reiche ihn runter.\n\nGute sichere Grenzen sind typischerweise Header-Bereich, Liste und Row-Item, Filter (nur Inputs), Footer-Steuerungen (Pagination, Totals, Bulk-Aktionen) und Dialoge (Open/Close und Callbacks reinreichen).\n\nNamen sind wichtiger, als viele denken. Wähle spezifische Namen wie `UsersTableHeader` oder `InvoiceRowActions`. Vermeide Sammelbezeichnungen wie „Utils“ oder „HelperComponent“, weil sie Verantwortlichkeiten verschleiern und dazu verleiten, Belange zu vermischen.\n\nFühre erst dann Container-Komponenten ein, wenn es wirklich nötig ist: ein UI-Block, der State oder Effekte besitzen muss, um kohärent zu bleiben. Selbst dann sollte er eng sein. Ein guter Container hat genau einen Zweck (z. B. „Filter-State“) und reicht den Rest als Props durch.\n\n## State und Effekte entwirren in kleinen, sicheren Schritten\n\nUnordentliche Komponenten mischen meist drei Datenarten: echter UI-State (was der Nutzer geändert hat), abgeleitete Daten (was du berechnen kannst) und Server-State (Daten aus dem Netzwerk). Wenn du alles als lokalen State behandelst, werden Refactors riskant, weil du unbeabsichtigt änderst, wann Dinge aktualisiert werden.\n\nBeginne damit, jede Datenstelle zu labeln. Frag: Bearbeitet der Nutzer das, oder kann ich es aus Props, State und gecachten Daten berechnen? Frag auch: Wird dieser Wert hier besessen, oder wird er nur durchgereicht?\n\n### State von abgeleiteten Werten trennen\n\nAbgeleitete Werte sollten nicht in `useState` leben. Verschiebe sie in eine kleine Funktion oder einen memoisierten Selektor, wenn es teuer ist. Das reduziert State-Updates und macht Verhalten vorhersehbarer.\n\nEin sicheres Muster:\n\n- Halte nur vom Nutzer bearbeitete Werte in `useState`.\n- Berechne view-only Werte aus diesen Eingaben.\n- Reiche berechnete Werte runter, nicht deren Setter, es sei denn, ein Kind bearbeitet sie wirklich.\n- Wenn Performance wichtig ist, umschließe teure Berechnungen mit `useMemo`.\n\n### Effekte langweilig und spezifisch machen\n\nEffekte brechen Verhalten, wenn sie zu viel tun oder auf die falschen Abhängigkeiten reagieren. Ziel ist: ein Effekt pro Zweck – einer fürs Syncen zu `localStorage`, einer fürs Fetching, einer für Subscriptions. Wenn ein Effekt viele Werte liest, versteckt er meist zusätzliche Verantwortlichkeiten.\n\nWenn du Claude Code nutzt, bitte um eine winzige Änderung: Splitte einen Effekt in zwei oder verschiebe eine Verantwortung in einen Helfer. Führe dann Charakterisierungstests nach jedem Schritt aus.\n\nAchte auf Prop-Drilling. Den mit Context zu ersetzen hilft nur, wenn es wiederholte Verkabelung entfernt und Ownership klarer macht. Ein gutes Zeichen ist, wenn Context nach einem App-weiten Konzept klingt (aktueller Nutzer, Theme, Feature-Flags) und nicht wie ein Workaround für einen Komponentenbaum.\n\nBeispiel: Eine Table-Komponente speichert sowohl `rows` als auch `filteredRows` im State. Behalte `rows` im State, berechne `filteredRows` aus `rows` plus `query` und halte die Filterlogik in einer reinen Funktion, damit sie leicht testbar und schwer zu brechen ist.\n\n## Checkpoints nutzen, um schnell revertieren zu können\n\nRefactors gehen meistens schief, wenn du zu viel änderst, bevor du es bemerkst. Die Lösung ist simpel: arbeite in winzigen Checkpoints und behandle jeden wie ein Mini-Release. Selbst wenn du in einem Branch arbeitest, halte deine Änderungen PR-groß, damit du sehen kannst, was kaputtging und warum.\n\nNach jedem sinnvollen Schritt (Komponente extrahiert, State-Fluss geändert) halte an und beweise, dass du das Verhalten nicht geändert hast. Dieser Beweis kann automatisiert (Tests) und manuell (schnelle Checks im Browser) erfolgen. Ziel ist nicht Perfektion, sondern schnelle Fehlererkennung.\n\nEine praktische Checkpoint-Schleife:\n\n- Mach eine kleine Änderung (eine Extraktion, einen State-Move, ein Effect-Cleanup).\n- Führe die Test-Suite aus oder zumindest die Charakterisierungstests für den Bereich.\n- Mach einen schnellen manuellen Spot-Check der wichtigsten Nutzerpfade.\n- Speichere einen Rollback-Punkt (git commit oder Plattform-Snapshot).\n\nWenn du eine Plattform wie Koder.ai benutzt, können Snapshots und Rollback wie Sicherheitsgeländer wirken, während du iterierst. Du willst trotzdem normale Commits, aber Snapshots helfen beim Vergleich einer „bekannten guten" Version mit deiner aktuellen, oder wenn ein Experiment danebengeht.\n\nFühre ein einfaches Verhaltens-Logbuch währenddessen. Es ist nur eine kurze Notiz dessen, was du verifiziert hast, und verhindert, dass du dieselben Dinge immer wieder prüfst.\n\nBeispiel:\n\n- Table-Sortierung: sortiert noch nach derselben Spalte und Icon zeigt Zustand korrekt.\n- Row-Selection: Auswahlanzahl aktualisiert sich, Bulk-Aktionen aktivieren korrekt.\n- Loading und Error: Spinner und Retry-Button erscheinen in denselben Fällen.\n\nWenn etwas kaputtgeht, sagt dir das Log, was du erneut prüfen musst, und deine Checkpoints machen das Revertieren günstig.\n\n## Häufige Fallen, die Verhalten während Refactors brechen\n\nDie meisten Refactors scheitern an kleinen, langweiligen Dingen. Die UI funktioniert größtenteils, aber eine Abstandsregel verschwindet, ein Klick-Handler feuert doppelt, oder eine Liste verliert Fokus beim Tippen. Assistenten können das verschlimmern, weil der Code sauberer aussieht, während Verhalten driftet.\n\nEine häufige Ursache ist Strukturänderung. Du extrahierst eine Komponente, wickelst Dinge in ein zusätzliches `\u003cdiv\u003e` oder tauschst ein `\u003cbutton\u003e` gegen ein klickbares `\u003cdiv\u003e`. CSS-Selektoren, Layout, Tastaturnavigation und Test-Queries können sich ändern, ohne dass es jemand merkt.\n\nDie Fallen, die Verhalten am häufigsten brechen:\n\n- DOM-Änderungen, die harmlos wirken: Extra-Wrapper, andere Elementtypen oder verschobene Attribute können CSS und Tests brechen. Behalte dieselben Tags und data-Attribute, bis du sie bewusst ändern willst.\n- Referentielle Gleichheit versehentlich brechen: Inline neu erstellte Objekte/Funktionen (`{}` oder `() => {}`) können Extra-Rerenders und Reset von Child-State auslösen. Achte auf Props, die früher stabil waren.\n- Hook-Dependency-Fehler: Logik in `useEffect`, `useMemo` oder `useCallback` zu verschieben kann stale Werte oder Loops erzeugen, wenn Abhängigkeiten falsch sind. Wenn ein Effekt früher „on click“ lief, verwandle ihn nicht in etwas, das „whenever anything changes“ läuft.\n- Verhalten ohne Erlaubnis upgraden: Edge-Cases „fixen“, Sortierregeln ändern oder Validierung verbessern ist Produktarbeit. Match das heutige Verhalten zuerst, auch wenn es merkwürdig ist.\n\nKonkretes Beispiel: Du teilst eine Table-Komponente auf und änderst die Row-Keys von einer ID zu einem Array-Index. Das sieht erst in Ordnung aus, kann aber Selection-State brechen, wenn Reihen neu geordnet werden. Betrachte „sauber" als Bonus. Behandle „gleiches Verhalten" als Requirement.\n\n## Schnelle Checkliste, bevor du abschließt\n\nBevor du merge, willst du Beweise, dass der Refactor das Verhalten beibehalten hat. Das einfachste Signal ist langweilig: alles funktioniert weiterhin, ohne dass du Tests „reparieren" musst.\n\nMach diesen schnellen Pass nach der letzten kleinen Änderung:\n\n- Alte Tests laufen ohne Änderungen, und deine neuen Charakterisierungstests bestehen ebenfalls (keine aktualisierten Snapshots, keine geänderten Assertions).\n- Die UI zeigt weiterhin dieselben sichtbaren Zustände: Loading, Empty, Error, Success, und sie treten unter denselben Bedingungen auf.\n- Öffentliche Props und Callback-Verträge blieben stabil: gleiche Namen, gleiche Argumentformen, gleiche Timing-Eigenschaften (z. B. feuert `onChange` weiterhin bei Nutzer-Input, nicht beim Mount).\n- Fokus- und Tastaturverhalten fühlt sich gleich an: Tab-Reihenfolge, Enter- und Escape-Handling und wohin der Fokus nach Aktionen wie Speichern, Schließen oder Pagination springt.\n- Analytics und Nebeneffekte passieren weiterhin einmal, zum selben Zeitpunkt wie vorher (z. B. ein „Viewed“-Event pro Screen-Load, nicht pro Re-Render).\n\nEin schneller Sanity-Check: Öffne die Komponente und mache einen merkwürdigen Ablauf, z. B. Fehler auslösen, erneut versuchen, dann Filter zurücksetzen. Refactors brechen oft Übergänge, selbst wenn der Hauptpfad funktioniert.\n\nWenn etwas fehlschlägt, revertiere die letzte Änderung und mache sie in einem kleineren Schritt neu. Das ist meist schneller als ein großes Diff zu debuggen.\n\n## Ein realistisches Beispiel: Eine unordentliche Table-Komponente aufteilen\n\nStell dir eine `ProductTable` vor, die alles macht: Daten laden, Filter verwalten, Pagination steuern, ein Bestätigungsdialog zum Löschen öffnen und Row-Aktionen wie Edit, Duplicate und Archive handhaben. Sie begann klein und wuchs zu einer 900-Zeilen-Datei.\n\nDie Symptome sind vertraut: State ist über mehrere `useState` verteilt, ein paar `useEffect`s laufen in einer bestimmten Reihenfolge, und eine „harmlose" Änderung bricht Pagination nur, wenn ein Filter aktiv ist. Leute fassen sie nicht mehr an, weil sie unberechenbar wirkt.\n\nBevor du Struktur änderst, sperre das Verhalten mit einigen Charakterisierungstests. Konzentriere dich auf Nutzeraktionen, nicht internen State:\n\n- Filter anwenden aktualisiert sichtbare Zeilen und setzt auf Seite 1 zurück.\n- Pagination behält Filter und zeigt korrekte Seitenanzahl.\n- Klick auf „Archive" deaktiviert die Zeile, während die Anforderung läuft.\n- Leerer Zustand zeigt, wenn keine Ergebnisse zu den Filtern passen.\n- Ladezustand flackert nicht „Keine Ergebnisse" auf.\n\nDann kannst du in kleinen Commits refactoren. Ein sauberer Extraktionsplan könnte so aussehen: `FilterBar` rendert Controls und emittiert Filter-Änderungen; `TableView` rendert Zeilen und Pagination; `RowActions` besitzt das Action-Menü und die Confirm-Dialog-UI; und ein `useProductTable` Hook besitzt die unordentliche Logik (Query-Params, abgeleiteter State und Nebeneffekte).\n\nDie Reihenfolge ist entscheidend. Extrahiere zuerst dumme UI (`TableView`, `FilterBar`) und reiche Props unverändert durch. Heb dir den riskanten Teil für zuletzt auf: State und Effekte in `useProductTable` verschieben. Halte alte Prop-Namen und Event-Formen, damit Tests weiterlaufen. Wenn ein Test fehlschlägt, hast du eine Verhaltensänderung gefunden, keinen Stilbruch.\n\n## Nächste Schritte: Diese Methode wiederholbar machen\n\nWenn du willst, dass das Refactoring mit Claude Code jedes Mal sicher ist, mach das Vorgehen zu einer kleinen Vorlage, die du wiederverwenden kannst. Ziel ist nicht mehr Prozess, sondern weniger Überraschungen.\n\n### Eine einfache Refactor-Vorlage behalten\n\nSchreibe ein kurzes Playbook, dem du bei jeder Komponente folgen kannst, auch wenn du müde oder gehetzt bist:\n\n- Formuliere das Ziel in einem Satz (was sich verbessert, was nicht geändert werden darf).\n- Halte aktuelles Verhalten mit Charakterisierungstests fest (inklusive ungewöhnlicher Randfälle).\n- Mach eine kleine Änderung (extrahieren, umbenennen, State verschieben, Effekte isolieren).\n- Führe Tests aus und mache einen schnellen manuellen UI-Check.\n- Speichere einen Checkpoint, zu dem du zurückkehren kannst, falls nötig.\n\nSpeichere das als Snippet in deinen Notizen oder im Repo, damit der nächste Refactor mit denselben Sicherheitsregeln beginnt.\n\n### Entscheide, was nach dem Verhalten-Sichern folgt\n\nWenn die Komponente stabil und leichter zu lesen ist, wähle den nächsten Schritt nach Nutzer-Relevanz. Eine übliche Reihenfolge ist: Accessibility zuerst (Labels, Fokus, Tastatur), dann Performance (Memoization, teure Renders), dann Cleanup (Types, Naming, toter Code). Mische nicht alle drei in einem PR.\n\nWenn du einen vibe-coding Workflow wie Koder.ai (koder.ai) nutzt, kann der Planungsmodus helfen, Schritte zu skizzieren, bevor du Code anfasst, und Snapshots/Rollback dienen als Checkpoints beim Iterieren. Am Ende erleichtert es der Export des Source-Codes, das finale Diff zu reviewen und eine saubere Historie zu behalten.\n\n### Weiß, wann du aufhören und ausliefern solltest\n\nHör auf zu refactoren, wenn Tests das Verhalten abdecken, vor dem du Angst hattest, die nächste Änderung ein Feature wäre oder du den Drang hast, im gleichen PR „perfekt" zu machen. Wenn das Aufteilen eines großen Formulars den verknoteten State entfernt hat und Tests Validierung und Submit abdecken, merge den Refactor. Lege verbleibende Ideen als kurze Backlog-Items ab.FAQ
Teilen