Mit Hooks zu saubereren React-Komponenten
Class-based Components oder das neue heiße Zeug? Ein kurzer Erfahrungsbericht zu React Hooks
Natürlich schlachten wir unseren Technologieträger Corona-Bäckerei weiter aus, um uns auch in Sachen React weiterzuentwickeln. Dieses Mal widmen wir uns dem Thema Hooks, eine (nicht mehr ganz so) neue Art, um state und Lifecycle-Methoden in Komponenten einzubinden. Um Eines vorweg zu nehmen: Wir sind ziemlich… nunja… hooked. In diesem kurzen Artikel möchten wir anhand eines einfaches Beispiels einen ganz knappen Überblick über die Unterschiede geben.
Was ist neu?
Eigentlich verbirgt sich hinter dem Thema React Hooks gar nicht so viel Magie. Hooks sind einfache Methodenaufrufe, mit denen sich z.B. auf state oder auf Methoden für das Setzen von state zugreifen lässt, während sich React unter der Haube um alles Weitere kümmert. Typischerweise gab es bisher die Unterscheidung zwischen Class-based Components und Stateless Functional Components. Diese Unterscheidung wird mit Hooks aufgeweicht, denn auch letztere bekommen durch Hooks eine schlanke Möglichkeit für state-Management — ohne den Mehraufwand von Syntax für eine neue Klasse. Das Ergebnis ist oft Code, der leichter zu lesen, zu verstehen und zu warten ist. Hooks gibt es in Form des useState
Hooks für den state einer Komponente und in Form des useEffect
Hooks für die Lifecycle-Methoden. Letztere waren vorher in Form von componentDidMount
, componentDidUpdate
und componentWillUnmount
separat.
Hooks sind also spezielle Funktionen, die es ermöglichen, sich in state- und Lifecycle-Features innerhalb von Functional Components „einzuhaken“. Was bis hier noch relativ abstrakt klingt, wird für den geneigten React-Entwickler klarer, sobald wir uns ein paar einfache Beispiele im Vorher-Nachher-Vergleich anschauen.
Coding Time!
Ein klassisches Beispiel, mit dem sich angehende React-Entwickler an die Library heranwagen, ist ein Zähler-Button. Da ein Zähler einen state benötigt und vergleichsweise einfach ist, eignet es sich super, um sich den useState
Hook genauer anzusehen.
Um so einen kleinen Counter abzubilden, brauchen wir einen count
als state mit einem Anfangswert von 0
und einen Button, mit dem sich je Klick der count
um eins erhöht. Ohne Hooks sieht der Syntax für eine Class-based Component so aus:
import React from ‘react’;
class Counter extends React.Component {
state = {
count: 0
};
handleClick = () => {
this.setState(({ count }) => ({
count: count + 1
}));
};
render() {
return {this.state.count};
}
}
Dem Aufruf der Funktion useState(0)
entnehmen wir sowohl den state count
mit dem Anfangswert 0
sowie eine Funktion setCount
, mit der dieser state überschrieben werden kann.
Dadurch, dass wir hier eine Variable count
unseres state und eine korrespondierende Funktion setCount
zum Überschreiben dieses state haben, ist der ganze Vorgang sehr explizit und verbessert die Leserlichkeit. Wenn später irgendwo im Code die Funktion setCount
aufgerufen wird, ist sofort klar, dass hier der state für count
überschrieben wird — anders als bei this.setState({count: … })
, wo der gesamte state manipuliert werden kann.
Beispiele mit useEffect
können zwar auch etwas komplex werden, sind aber dennoch häufig leserlicher als die Verwendung von mehreren Lifecycle-Methoden. Der Name useEffect kommt daher, dass in React externe API-Calls, direkte Interaktion mit dem DOM oder auch das Aufsetzen von Subscriptions als sogenannte “Side Effects” bezeichnet werden. Auch wenn diese Bezeichnung etwas ungewohnt ist, ist deren Durchführung in Komponenten völlig alltäglich.
Was also ohne Hooks in componentDidMount
, componentDidUpdate
und componentWillUnmount
durchgeführt wurde, lässt sich mit dem useEffect
Hook abbilden.
Wollen wir in unserem Counter-Beispiel also den Titel der Webseite mit jedem Klick anpassen, sähe das traditionell so aus:
import React from ‘react’;
class Counter extends React.Component {
state = {
count: 0
};
handleClick = () => {
this.setState(({ count }) => ({
count: count + 1
}));
};
componentDidMount() {
document.title = `You clicked ${this.state.count} times`;
}
componentDidUpdate() {
document.title = `You clicked ${this.state.count} times`;
}
render() {
return ;
}
}
Wohingegen die Hooks-Alternative so aussähe:
import React, { useEffect, useState } from ‘react’;
const Counter = () => {
const [count, setCount] = useState(0)
useEffect(() => {
document.title = `You clicked ${count} times`;
});
return ;
}
In diesem einfachen Beispiel wird useEffect
immer ausgeführt, wenn sich irgendwas in der Komponente ändert und sie neu gerendert wird. Das ist natürlich nicht immer gewollt und lässt sich bei Bedarf auch steuern.
Ein entscheidender Vorteil ist, dass useEffect
auch mehrfach verwendet werden kann und sich so unterschiedliche Side Effects separat abfrühstücken lassen — Im Vergleich zu mit if-Statements vollgepackten Lifecycle-Methoden.
Hier muss doch irgendwo ein Haken sein… (höhö)
Wer die Unterscheidung zwischen Stateless Functional Components und Class-based Components lieb gewonnen hat, für den oder die gibt es keinen Grund zur Panik: Hooks sind vollständig auf Opt-in-Basis und 100% rückwärtskompatibel. Das bedeutet, dass es keinen Zwang gibt, Hooks sofort zu lernen oder zu verwenden. Wer also alten Code und bestehende Komponenten auf den neuen Syntax mit Hooks migrieren möchte oder ein Refactoring plant, muss keine Inkompatibilitäten fürchten. So ergibt sich die schöne Möglichkeit, sukzessive und je nach Situation alten Code auf Hooks zu migrieren — ganz ohne Zwang, direkt alle Code-Teile neu anfassen zu müssen.
Es gibt derzeit auch nicht den Plan, den klassenbasierten Syntax in React abzuschaffen. React Hooks sind viel mehr eine alternative API, die helfen soll, ein paar der gängigsten Probleme in React zu lösen.
Sie brauchen Unterstützung bei der Umsetzung Ihres Frontends?
Als Spezialisten im E-Commerce mit langjähriger Erfahrung mit großen Kunden bieten wir von der Plattformentwicklung bis zur Performanceoptimierung umfangreiche E-Commerce-Lösungen und Beratungsangebote zu Softwaretechnologien.
Oder möchten Sie mehr zum Thema React und dessen Einsatz im E-Commerce lesen?
Auf unserem Blog finden Sie weitere spannende Eindrücke, beispielsweise zur Performance-Optimierung von Online-Shops mit dem JAMStack oder einem Vergleich von React zum Cross-Platform-Framework Flutter.