In modernen React-Anwendungen wird der globale Zustand häufig über den Context-API verwaltet, um die Notwendigkeit zu vermeiden, Props manuell über mehrere Ebenen zu übergeben. Dieser Ansatz trägt zur Vereinfachung des Codes bei, insbesondere in komplexeren Anwendungen, in denen zahlreiche Komponenten denselben Zustand benötigen. In diesem Zusammenhang betrachten wir, wie der Benutzername als globaler Zustand in einer Blog-App mithilfe von React Context implementiert wird.
Das Muster, das hier angewendet wird, wird als Inversion of Control bezeichnet. Es ermöglicht eine saubere Handhabung von Zuständen, ohne sie durch jede Ebene von Komponenten zu propagnieren. Dennoch sollte dieses Muster mit Bedacht verwendet werden, da es die höherliegenden Komponenten komplexer machen kann. Wie bei jedem Designmuster gibt es auch hier Grenzen, und es ist nicht immer die beste Wahl.
Nachdem wir bereits gelernt haben, wie man den Kontext für das Implementieren von Themen in einer Blog-App einsetzt, konzentrieren wir uns nun darauf, wie der Benutzername als globaler Zustand verwaltet wird. Der Benutzername ist eine Variable, die über die gesamte Anwendung hinweg benötigt wird und nicht häufig geändert wird, was sie zu einem idealen Kandidaten für den Einsatz von Context macht.
Definieren des Contexts
Zunächst müssen wir den Context definieren. Dies erfolgt mit der Funktion createContext aus React. Der Context wird mit einem Standardwert initialisiert, der ein Array enthält: das erste Element des Arrays ist ein leerer String (der Standardwert des Benutzernamens), das zweite Element ist eine "No-Op"-Funktion, also eine Funktion, die nichts tut. Dieser Standardwert stellt sicher, dass der Context auch ohne einen Provider einen gültigen Wert liefert.
Um den Context zu definieren, erstellen wir eine Datei namens UserContext.js, die die Context-Definition enthält:
Der UserContext stellt nun den globalen Zustand des Benutzernamens sowie eine Methode zum Aktualisieren dieses Zustands zur Verfügung.
Implementieren des Context Providers
Nun müssen wir einen Provider definieren, der den Wert des Benutzernamens und die Funktion zum Setzen des Benutzernamens an die restliche Anwendung weitergibt. In der App.jsx-Datei importieren wir den Context und umhüllen die Hauptkomponente mit dem UserContext.Provider, um den Zustand für alle darunter liegenden Komponenten zugänglich zu machen.
Dieser Provider sorgt dafür, dass der username-Zustand und die zugehörige Funktion setUsername über den Context allen Komponenten in der App zugänglich gemacht werden.
Refaktorisierung der Komponenten
Nun, da der Context-Provider konfiguriert ist, können wir die Komponenten der Anwendung refaktorisieren, um den Zustand über den Context abzurufen, anstatt ihn per Props weiterzugeben. Ein Beispiel ist die UserBar-Komponente, die den Benutzernamen anzeigen soll. Hierzu verwenden wir den useContext-Hook, um den Zustand aus dem UserContext zu lesen:
Durch diese Anpassung entfällt das manuelle Übergeben des Benutzernamens als Prop, was den Code erheblich vereinfacht und die Wiederverwendbarkeit der Komponenten verbessert.
Ähnlich wie bei der UserBar-Komponente können auch andere Komponenten, wie Login, Logout oder Register, den Context nutzen, um den Benutzernamen und die zugehörige Funktion zum Aktualisieren des Benutzernamens zu erhalten. Dies führt zu einem klareren, besser wartbaren Code.
Vorteile der Verwendung von Context
Der größte Vorteil, den der Einsatz von Context mit sich bringt, liegt in der Reduktion der Komplexität, die durch das manuelle Weitergeben von Props durch viele Komponenten entsteht. Dies ist besonders bei größeren Anwendungen nützlich, wo der Zustand über viele Ebenen hinweg weitergegeben werden muss. Der Context ermöglicht es, diese Zustände auf einer höheren Ebene zentral zu verwalten und auf allen darunter liegenden Komponenten zugänglich zu machen, ohne sie explizit als Props weitergeben zu müssen.
Ein weiterer Vorteil ist die Flexibilität, die der useContext-Hook bietet. Dadurch können wir den Zustand aus dem Context auf einfache Weise in unseren Komponenten verwenden, ohne auf komplexe HOC (Higher Order Components) oder Render Props angewiesen zu sein, wie es bei älteren Versionen von React der Fall war.
Grenzen von Context
Dennoch ist es wichtig, den Einsatz von Context mit Bedacht zu wählen. Nicht jeder Zustand sollte über Context verwaltet werden. Besonders in Fällen, in denen der Zustand nur in einer begrenzten Anzahl von Komponenten verwendet wird oder sich häufig ändert, kann der Einsatz von Context zu unnötiger Komplexität führen. In solchen Fällen könnte die Verwendung von useState und useEffect oder anderen State-Management-Techniken wie Redux sinnvoller sein.
Ein weiteres Problem bei der Verwendung von Context tritt auf, wenn zu viele Komponenten auf den gleichen Context zugreifen. Dies kann zu einer unnötigen Neuberechnung und damit zu Leistungseinbußen führen, besonders wenn der Context häufig geändert wird. Hier sollte man in Erwägung ziehen, den globalen Zustand auf kleinere, spezialisierte Contexts aufzuteilen oder andere Strategien zur Optimierung der Leistung zu verwenden.
Fazit
Durch den Einsatz von React Context können wir den globalen Zustand effizient verwalten und den Code erheblich vereinfachen. Dies ist besonders nützlich in größeren Anwendungen, in denen viele Komponenten denselben Zustand benötigen. Der Context ermöglicht es uns, diese Zustände zentral zu verwalten und sie über den gesamten Komponentenbaum hinweg zugänglich zu machen, ohne sie explizit weitergeben zu müssen.
Es ist jedoch wichtig, Context mit Bedacht einzusetzen und sicherzustellen, dass er nur für Zustände verwendet wird, die wirklich global sind und nicht zu häufig geändert werden. Für andere Fälle bieten sich alternative Lösungen wie lokale States oder komplexere State-Management-Tools an.
Wie man React-Hooks testet: Einrichtung und Praxisbeispiele
Das Testen von React-Hooks ist eine wichtige Aufgabe, um sicherzustellen, dass die Funktionen innerhalb einer React-Anwendung korrekt und zuverlässig arbeiten. Früher gab es zwei separate Bibliotheken: die React Testing Library und die React Hooks Testing Library. Heute jedoch enthält die React Testing Library bereits die Unterstützung für Hooks, sodass es nicht mehr nötig ist, eine zusätzliche Bibliothek zu verwenden. Die React Hooks Testing Library ist mittlerweile veraltet, und daher verwenden wir nur noch die React Testing Library.
Es gibt mehrere Szenarien, in denen das Testen von Hooks besonders wichtig ist:
-
Wenn man eine Bibliothek schreibt, die Hooks definiert und exportiert.
-
Wenn Hooks in mehreren Komponenten verwendet werden.
-
Wenn ein Hook komplex ist und es später schwierig sein könnte, ihn zu ändern oder zu refaktorisieren.
Für Hooks, die spezifisch für eine einzelne Komponente sind, ist es häufig sinnvoller, direkt die Komponente zu testen. Das Testen von Komponenten an sich ist jedoch nicht der Fokus dieses Textes. Weitere Informationen zum Testen von Komponenten findet man auf der Webseite der React Testing Library.
Bevor wir jedoch mit dem Testen beginnen, müssen wir die notwendige Umgebung einrichten. Dies erfordert das Setzen von Vitest und der React Testing Library.
Einrichtung von Vitest und React Testing Library
-
Zunächst müssen wir den Ordner "Chapter12_4" in einen neuen Ordner "Chapter12_5" kopieren:
-
Öffnen Sie den neuen Ordner in Visual Studio Code.
-
Installieren Sie Vitest, die React Testing Library und jsdom mit folgendem Befehl:
jsdomstellt eine Umgebung zur Verfügung, um den DOM in Node.js zu simulieren, da unsere Tests nicht in einem echten Browser laufen. -
Bearbeiten Sie die
package.jsonund fügen Sie ein Skript zum Ausführen von Vitest hinzu: -
Bearbeiten Sie die
vite.config.js, um die Konfiguration für Vitest hinzuzufügen:
Nun haben wir die Umgebung eingerichtet und können mit dem Testen von Hooks beginnen.
Testen eines einfachen Hooks
Lassen Sie uns nun einen einfachen Hook erstellen und testen. Der erste Schritt besteht darin, einen Hook namens useCounter zu definieren, der einen Zählerwert zurückgibt und Funktionen zum Erhöhen und Zurücksetzen des Zählers bietet.
Erstellen des useCounter Hooks
-
Erstellen Sie eine neue Datei
src/hooks/counter.jsund importieren Sie dieuseStateFunktion: -
Definieren Sie den Hook
useCounter, der eineninitialCountals Argument entgegennimmt: -
Fügen Sie eine Funktion
incrementhinzu, die den Zähler um 1 erhöht: -
Fügen Sie eine Funktion
resethinzu, die den Zähler auf deninitialCountzurücksetzt: -
Geben Sie schließlich den aktuellen Zählerwert und die beiden Funktionen zurück:
Nun haben wir unseren einfachen Hook erstellt. Es ist Zeit, Unit-Tests für diesen Hook zu schreiben.
Erstellen von Unit-Tests für den useCounter Hook
-
Erstellen Sie eine neue Datei
src/hooks/counter.test.js. -
Importieren Sie die notwendigen Funktionen von Vitest sowie die Funktionen
renderHookundactaus der React Testing Library: -
Definieren Sie eine Gruppe von Tests für den
CounterHook: -
Beginnen Sie mit einem einfachen Test, der überprüft, ob der Zähler standardmäßig auf 0 gesetzt ist:
Hier verwenden wir
renderHook, um den Hook in einer simulierten Komponente darzustellen. Dieresult.current.countgibt uns den aktuellen Wert des Zählers zurück, den wir dann mitexpectüberprüfen. -
Als nächstes testen wir, ob der
initialCountkorrekt funktioniert: -
Ein weiterer Test überprüft, ob die
incrementFunktion den Zähler korrekt erhöht: -
Schließlich testen wir, ob der Zähler nach einem
resetwieder auf den ursprünglichen Wert zurückgesetzt wird: -
Führen Sie die Tests mit folgendem Befehl aus:
Ergänzende Informationen zum Testen von Hooks
Beim Testen von Hooks sollten verschiedene Aspekte berücksichtigt werden, um sicherzustellen, dass sie korrekt funktionieren. Besonders wichtig ist die korrekte Handhabung von Zuständen und die Nutzung von Funktionen wie act, um sicherzustellen, dass alle Änderungen im Zustand auch tatsächlich in den Tests berücksichtigt werden. Ein weiteres wichtiges Konzept beim Testen von Hooks ist das Testen von asynchronem Verhalten und das Überprüfen der Ausführung von Effekten, die in komplexeren Hooks vorkommen können.

Deutsch
Francais
Nederlands
Svenska
Norsk
Dansk
Suomi
Espanol
Italiano
Portugues
Magyar
Polski
Cestina
Русский