State Management in React 16.8

Wie Patrick euch bereits in seinem letzten Post von April berichtet hat, haben wir vor einiger Zeit React als unser primäres Framework für die Webentwicklung gewählt. Heute möchte ich ein bisschen mehr über die Gründe unserer Entscheidung und unsere Pläne für die Implementierung von State in unseren Projekten erzählen.

Die Entscheidung haben wir getroffen, weil wir React als die derzeit vielversprechendste Technologie ansehen. Außerdem verwenden wir auch teilweise React Native für die Mobile App-Entwicklung, und durch den Wechsel zu React konnten wir einige Synergien zwischen den Web- und Mobile-Teams schaffen. Anfänglich nutzten wir MobX für das State Management in unseren Anwendungen, aber mit dem Release von Hooks in React 16.8 entschieden wir uns für den Wechsel zum reinen React State Management mit den Hooks und Context APIs.

Warum nicht mehr MobX?

Obwohl MobX ein unglaublich gutes Framework für das State Management in React Anwendungen ist, basiert dessen Implementierung auf Klassen-Komponenten, die leider mit der neu vorgestellten Hook API inkompatibel sind. Unserer Meinung nach bringen Hooks aber eine ordentliche Verbesserung für das Schreiben von wiederverwendbarer Logik und die Reduzierung von Code-Komplexität. Wenn man außerdem den Entwicklern von React Glauben schenken darf, sind Hooks die Zukunft und somit sollten von jetzt an alle Komponenten auf diese API aufbauen. Diese und noch einige weitere Gründe haben uns also schließlich dazu bewogen, auf MobX zu verzichten, uns voll auf die Nutzung von Hooks in unseren Projekten einzulassen und Reacts eigenes State Management System zu nutzen.

An dieser Stelle sollte noch erwähnt werden, dass mit MobX Lite bereits eine alternative Möglichkeit existiert, die Hooks unterstützt und darüber hinaus noch eigene State Management Funktionalität bietet. Für unsere Zwecke sehen wir darin aber keine wesentlichen Vorteile und haben uns daher für die von React „out-of-the-box“ zur Verfügung gestellte API entschieden.

Hooks

Die neue Hooks API liefert einige unglaubliche Funktionen und Vorteile, wie beispielsweise Effect Hooks für das Implementieren von Nebeneffekten, Context Hooks für die Integration des Context Systems in die neue API, Memorization Hooks für Callbacks und Daten und noch einiges mehr. Eine detaillierte Beschreibung aller verschiedenen Hooks würde hier allerdings zu weit gehen, also konzentrieren wir uns für den Moment auf jene Hooks, die für das State Management am nützlichsten sind – State Hooks und Context Hooks.

State Hooks sind die Weiterentwicklung des lokalen State Managements in React vor der Einführung von Hooks. Die gesamte Funktionalität von State Hooks kann mit der folgenden Codezeile aufgerufen werden:

const [value, setValue] = useState( 42 );

Der einzige Parameter der Funktion ist der anfängliche Wert mit dem der State initialisiert werden sollte. Das zurückgelieferte Array kann destrukturiert werden, um den aktuellen Wert des States als erstes Element und eine Funktion um den State zu modifizieren als zweites Element zu erhalten.

Das liefert uns wiederum alles was wir für das lokale State Management unserer Komponenten benötigen. Es ist das Äquivalent zu den state und setState Membern von Klassenkomponenten, kann aber auch bei Funnktionskomponenten verwendet werden.

Context

In jedem Projekt kommt irgendwann der Punkt, an dem man irgendeine Art von globalem State implementieren muss, obwohl dies normalerweise so lange wie möglich vermieden werden sollte, weil globaler State dazu neigt, das Testen von Komponenten ziemlich mühsam zu machen.

Theoretisch lässt sich global State auch schon realisieren in dem man State auf einer Root-Komponente einrichtet und als prop durch die Komponentenhierarchie zieht. Für kleine Projekte kann dies durchaus eine valide Strategie sein, aber mit zunehmender Projektgröße wird diese Vorgehensweise immer unzumutbarer, weil sogar Zwischenkomponenten, die nur props weitergeben, den vollen State kennen müssen, der möglicherweise von ihren Kindern benötigt wird.

Diese Problemstellung kann durch die Nutzung der Context API vermieden werden, welche eben genau für die Datenweitergabe durch die Komponentenhierarchie verantwortlich ist. Als erster Schritt muss der Kontext erstellt werden:

const UserContext = createContext({name: "Donald Truck" });

Der Parameter, der bei der Erstellung der Methode mitgegeben wird, definiert den Standardwert, welcher aber nur dann verwendet wird, wenn kein anderer Wert durch einen Context Provider zur Verfügung gestellt wird. Der erstellte Kontext alleine hat allerdings nur sehr wenig Nutzen. Um ihn tatsächlich für das globale State Management zu nutzen, müssen wir den State irgendwo in der Komponentenhierarchie erstellen und ihn an alle Komponenten weiter unten in der Hierarchie weitergeben.

const [user, setUser] = useState({name: "Doug Obert" });
return (
< UserContext.Provider value= {user} >
<..>
</ UserContext.Provider >
);

Dann können wir den Context auf jeder Ebene weiter unten in der Hierarchie abrufen. Vor der Einführung von Hooks musste dies mit Context Consumer Komponenten gemacht werden, aber nun bietet React 16.8 auch einen Context Hook, der den Zugriff auf den Kontext vereinfacht: const user = useContext(UserContext);

Der somit erhaltene Wert ist jener Wert, der vom nächsthöheren Context Provider in der Hierarchie zurückgegeben wird. Wir können den Contexts jede beliebige Eigenschaft mitgeben, sodass wir für die Komponenten auch Funktionen zur Modifikation des globalen States hinzufügen können.

Fazit

Dieser Blogpost sollte dir zeigen, dass State Management in React 16.8 ohne zusätzliche Frameworks erzielt werden kann. Und das obendrein mit einer API, die praktisch zu nutzen ist und viele Funktionalitäten für komplexe Szenarien liefert. Ob der Möglichkeiten, die sich durch die Hooks eröffnen, sind wir ehrlich gesagt ziemlich aufgeregt, und wir freuen uns schon darauf, euch zukünftig davon zu berichten, wie unser Code durch unsere Entscheidung beeinflusst wurde.