Best Practices mit React Hooks
Veröffentlicht: 2022-03-10 React Hooks sind eine neue Ergänzung in React 16.8, mit der Sie Status- und andere React-Funktionen verwenden können, ohne eine class
zu schreiben. Mit anderen Worten, Hooks sind Funktionen, mit denen Sie sich in React-Zustands- und Lebenszyklusfunktionen von Funktionskomponenten einklinken können. (Sie funktionieren nicht innerhalb von class
.)
React bietet einige eingebaute Hooks wie useState
. Sie können auch Ihre eigenen Hooks erstellen, um zustandsbehaftetes Verhalten zwischen verschiedenen Komponenten wiederzuverwenden. Das folgende Beispiel zeigt einen Zähler, dessen Zustand mit dem useState()
Hook verwaltet wird. Jedes Mal, wenn Sie auf die Schaltfläche klicken, verwenden wir setCount()
, um den Wert von count
um 1
zu aktualisieren.
Dieses Beispiel rendert einen Zähler mit dem Wert 0
. Wenn Sie auf die Schaltfläche klicken, wird der Wert um 1
erhöht. Der Anfangswert der Komponente wird mit useState
definiert.
const [count, setCount] = useState(0)
Wie Sie sehen können, setzen wir das auf 0
. Dann verwenden wir die Methode onClick()
, um setCount
wenn wir den Wert erhöhen möchten.
<button onClick={() => setCount(count + 1)}> Click me </button>
Vor der Veröffentlichung von React Hooks hätte dieses Beispiel mehr Codezeilen verwendet, da wir eine class
hätten verwenden müssen.
Regeln für Reaktionshaken
Bevor wir tief in die Best Practices eintauchen, müssen wir die Regeln von React Hooks verstehen, die auch einige der grundlegenden Konzepte der in diesem Artikel vorgestellten Praktiken sind.
React Hooks sind JavaScript-Funktionen, aber Sie müssen zwei Regeln befolgen, wenn Sie sie verwenden.
- Call Hooks auf der obersten Ebene;
- Rufen Sie nur Hooks von React-Komponenten auf.
Hinweis : Diese beiden Regeln wurden in React Hooks eingeführt, anstatt Teil von JavaScript selbst zu sein.
Sehen wir uns diese Regeln genauer an.
Anrufhaken auf der obersten Ebene
Rufen Sie Hooks nicht innerhalb von Schleifen, Bedingungen oder verschachtelten Funktionen auf. Verwenden Sie Hooks immer auf der obersten Ebene Ihrer React-Funktion. Indem Sie diese Regel befolgen, stellen Sie sicher, dass Hooks jedes Mal in derselben Reihenfolge aufgerufen werden, wenn eine Komponente gerendert wird. Das ermöglicht es React, den Status von Hooks zwischen mehreren useState
und useEffect
Aufrufen korrekt beizubehalten.
Lassen Sie uns eine Form
-Komponente erstellen, die zwei Zustände haben wird:
-
accountName
-
accountDetail
Diese Zustände haben Standardwerte, wir verwenden den useEffect
Hook, um den Zustand entweder im lokalen Speicher unseres Browsers oder im Titel unseres Dokuments zu speichern.
Nun, diese Komponente wird vielleicht ihren Zustand erfolgreich verwalten, wenn er zwischen mehreren Aufrufen von useState
und useEffect
gleich bleibt.
function Form() { // 1. Use the accountName state variable const [accountName, setAccountName] = useState('David'); // 2. Use an effect for persisting the form useEffect(function persistForm() { localStorage.setItem('formData', accountName); }); // 3. Use the accountDetail state variable const [accountDetail, setAccountDetail] = useState('Active'); // 4. Use an effect for updating the title useEffect(function updateStatus() { document.title = accountName + ' ' + accountDetail; }); // ... }
Wenn sich die Reihenfolge unserer Hooks ändert (was möglich sein kann, wenn sie in Schleifen oder Bedingungen aufgerufen werden), wird es React schwer fallen, herauszufinden, wie der Zustand unserer Komponente beibehalten werden kann.
// ------------ useState('David') // 1. Initialize the accountName state variable with 'David' useEffect(persistForm) // 2. Add an effect for persisting the form useState('Active') // 3. Initialize the accountdetail state variable with 'Active' useEffect(updateStatus) // 4. Add an effect for updating the status // ------------- // Second render // ------------- useState('David') // 1. Read the accountName state variable (argument is ignored) useEffect(persistForm) // 2. Replace the effect for persisting the form useState('Active') // 3. Read the accountDetail state variable (argument is ignored) useEffect(updateStatus) // 4. Replace the effect for updating the status // ...
Das ist die Reihenfolge, der React folgt, um unsere Hooks aufzurufen. Da die Reihenfolge gleich bleibt, kann sie den Zustand unserer Komponente bewahren. Aber was passiert, wenn wir einen Hook-Call in eine Bedingung einfügen?
// We're breaking the first rule by using a Hook in a condition if (accountName !== '') { useEffect(function persistForm() { localStorage.setItem('formData', accountName); }); }
Die Bedingung accountName !== ''
ist beim ersten Rendern true
, also führen wir diesen Hook aus. Beim nächsten Rendern kann der Benutzer jedoch das Formular löschen, wodurch die Bedingung auf false
wird. Da wir diesen Hook nun beim Rendern überspringen, ändert sich die Reihenfolge der Hook-Aufrufe:
useState('David') // 1. Read the accountName state variable (argument is ignored) // useEffect(persistForm) // This Hook was skipped! useState('Active') // 2 (but was 3). Fail to read the accountDetails state variable useEffect(updateStatus) // 3 (but was 4). Fail to replace the effect
React wüsste nicht, was für den zweiten useState
Hook-Aufruf zurückgegeben werden soll. React hat erwartet, dass der zweite Hook-Aufruf in dieser Komponente dem persistForm
Effekt entspricht, genau wie beim vorherigen Rendern – aber das ist nicht mehr der Fall. Von diesem Zeitpunkt an verschiebt sich jeder nächste Hook
-Anruf nach dem, den wir übersprungen haben, ebenfalls um eins – was zu Fehlern führt.
Aus diesem Grund müssen Hooks auf der obersten Ebene unserer Komponenten aufgerufen werden. Wenn wir einen Effekt bedingt ausführen möchten, können wir diese Bedingung in unseren Hook einfügen.
Hinweis : Sehen Sie sich die React Hook-Dokumentation an, um mehr zu diesem Thema zu lesen.
Rufen Sie nur Hooks von React-Komponenten auf
Rufen Sie keine Hooks von regulären JavaScript-Funktionen auf. Stattdessen können Sie Hooks von React-Funktionskomponenten aufrufen. Schauen wir uns unten den Unterschied zwischen der JavaScript-Funktion und der React-Komponente an:
JavaScript-Funktion
import { useState } = "react"; function toCelsius(fahrenheit) { const [name, setName] = useState("David"); return (5/9) * (fahrenheit-32); } document.getElementById("demo").innerHTML = toCelsius;
Hier importieren wir den useState
Hook aus dem React-Paket und deklarieren dann unsere Funktion. Dies ist jedoch ungültig, da es sich nicht um eine React-Komponente handelt.
Reaktionsfunktion
import React, { useState} from "react"; import ReactDOM from "react-dom"; function Account(props) { const [name, setName] = useState("David"); return <p>Hello, {name}! The price is <b>{props.total}</b> and the total amount is <b>{props.amount}</b></p> } ReactDom.render( <Account total={20} amount={5000} />, document.getElementById('root') );
Obwohl der Körper von beiden ähnlich aussieht, wird letzterer zu einer Komponente, wenn wir React in die Datei importieren. Dies macht es uns möglich, Dinge wie JSX und React-Hooks im Inneren zu verwenden.
Wenn Sie Ihren bevorzugten Hook zufällig importiert haben, ohne React zu importieren (was es zu einer regulären Funktion macht), können Sie den importierten Hook nicht verwenden, da auf den Hook nur in der React-Komponente zugegriffen werden kann.
Rufen Sie Hooks von benutzerdefinierten Hooks auf
Ein benutzerdefinierter Hook ist eine JavaScript-Funktion, deren Name mit use
beginnt und die andere Hooks aufrufen kann. Zum Beispiel wird useUserName
unter einem benutzerdefinierten Hook verwendet, der die useState
und useEffect
. Es ruft Daten von einer API ab, durchläuft die Daten und ruft setIsPresent()
auf, wenn der spezifische Benutzername, den es erhalten hat, in den API-Daten vorhanden ist.
export default function useUserName(userName) { const [isPresent, setIsPresent] = useState(false); useEffect(() => { const data = MockedApi.fetchData(); data.then((res) => { res.forEach((e) => { if (e.name === userName) { setIsPresent(true); } }); }); }); return isPresent; }
Wir können dann die Funktionalität dieses Hooks an anderen Stellen wiederverwenden, wo wir sie in unserer Anwendung benötigen. An solchen Stellen müssen wir, außer bei Bedarf, useState
oder useEffect
nicht mehr aufrufen.
Indem Sie diese Regel befolgen, stellen Sie sicher, dass die gesamte zustandsbehaftete Logik in einer Komponente aus ihrem Quellcode klar ersichtlich ist.
ESLint-Plugin
Das ESLint-Plugin namens eslint-plugin-react-hooks
erzwingt die oben genannten Regeln. Dies ist praktisch, um die Regeln bei der Arbeit an einem Projekt durchzusetzen. Ich schlage vor, dass Sie dieses Plugin verwenden, wenn Sie an Ihrem Projekt arbeiten, insbesondere wenn Sie mit anderen zusammenarbeiten. Sie können dieses Plugin zu Ihrem Projekt hinzufügen, wenn Sie es ausprobieren möchten:
// Your ESLint configuration { "plugins": [ // ... "react-hooks" ], "rules": { // ... "react-hooks/rules-of-hooks": "error", // Checks rules of Hooks "react-hooks/exhaustive-deps": "warn" // Checks effect dependencies } }
Dieses Plugin ist standardmäßig in Create React App enthalten. Sie müssen es also nicht hinzufügen, wenn Sie Ihre React-Anwendungen mit Create-React-App booten.
In Haken denken
Werfen wir einen kurzen Blick auf class
und funktionale Komponenten (mit Hooks), bevor wir uns mit den wenigen Best Practices für Hooks befassen.
Der einfachste Weg, eine Komponente in React zu definieren, besteht darin, eine JavaScript-Funktion zu schreiben, die ein React-Element zurückgibt:
function Welcome(props) { return <h1>Hello, {props.name}</h1>; }
Die Welcome
-Komponente akzeptiert props
, ein Objekt, das Daten enthält und ein React-Element zurückgibt. Wir können diese Komponente dann in eine andere Komponente importieren und rendern.
Die class
verwendet eine Programmiermethode namens Encapsulation , was im Grunde bedeutet, dass alles, was für die Klassenkomponente relevant ist, darin enthalten ist. Lebenszyklusmethoden ( constructors
, componentDidMount()
, render
usw.) verleihen Komponenten eine vorhersagbare Struktur.
Kapselung ist eine der Grundlagen von OOP (Object- Oriented P rogramming ) . Es bezieht sich auf die Bündelung von Daten innerhalb der Methoden, die mit diesen Daten arbeiten, und wird verwendet, um die Werte oder den Status eines strukturierten Datenobjekts innerhalb einer Klasse zu verbergen, wodurch der direkte Zugriff von Unbefugten auf sie verhindert wird.
Mit Hooks ändert sich die Zusammensetzung einer Komponente von einer Kombination aus Lebenszyklus-Hooks zu Funktionalitäten mit etwas Rendering am Ende.
Funktionskomponente
Das folgende Beispiel zeigt, wie benutzerdefinierte Hooks in einer funktionalen Komponente verwendet werden können (ohne zu zeigen, was der Körper ist). Was es tut oder kann, ist jedoch nicht beschränkt. Es könnte das Instanziieren von Zustandsvariablen, das Konsumieren von Kontexten, das Abonnieren der Komponente für verschiedene Nebenwirkungen sein – oder alles oben Genannte, wenn Sie einen benutzerdefinierten Hook verwenden!
function { useHook{...}; useHook{...}; useHook{...}; return (
...); }
Klasse Komponente
Eine class
erfordert, dass Sie React.Component
erweitern und eine render
erstellen, die ein React-Element zurückgibt. Dies erfordert mehr Code, bietet Ihnen aber auch einige Vorteile.
class { constructor(props) {...} componentDidMount() {...} componentWillUnmount() {...} render() {...} }
Es gibt einige Vorteile, die Sie durch die Verwendung funktionaler Komponenten in React erhalten:
- Es wird einfacher, Container- und Präsentationskomponenten zu trennen, da Sie mehr über den Status Ihrer Komponente nachdenken müssen, wenn Sie keinen Zugriff auf
setState()
in Ihrer Komponente haben. - Funktionale Komponenten sind viel einfacher zu lesen und zu testen, da es sich um einfache JavaScript-Funktionen ohne Status- oder Lebenszyklus-Hooks handelt.
- Am Ende haben Sie weniger Code.
- Das React-Team erwähnte, dass es in zukünftigen React-Versionen möglicherweise eine Leistungssteigerung für funktionale Komponenten geben wird.
Dies führt zu den ersten Best Practices bei der Verwendung von React Hooks.
Best Practices für Hooks
1. Vereinfachen Sie Ihre Haken
Wenn Sie React Hooks einfach halten, können Sie effektiv steuern und manipulieren, was in einer Komponente während ihrer gesamten Lebensdauer vor sich geht. Vermeiden Sie es so weit wie möglich, benutzerdefinierte Hooks zu schreiben ; Sie können ein useState()
oder useEffect()
, anstatt Ihren eigenen Hook zu erstellen.
Wenn Sie feststellen, dass Sie eine Reihe von benutzerdefinierten Hooks verwenden, die in ihrer Funktionalität verwandt sind, können Sie einen benutzerdefinierten Hook erstellen, der als Wrapper für diese fungiert. Schauen wir uns unten zwei verschiedene Funktionskomponenten mit Haken an.
Funktionskomponente v1
function { useHook(...); useHook(...); useHook(...); return( <div>...</div> ); }
Funktionskomponente v2
function { useCustomHook(...); useHook(...); useHook(...); return( <div>...</div> ); }
v2 ist eine bessere Version, da es den Hook einfach hält und alle anderen useHook
entsprechend inline sind. Dies ermöglicht es uns, Funktionen zu erstellen, die über verschiedene Komponenten hinweg wiederverwendet werden können, und gibt uns auch mehr Möglichkeiten, unsere Komponenten effektiv zu steuern und zu manipulieren. Anstatt v1 zu übernehmen, in dem unsere Komponenten mit Hooks übersät sind, sollten Sie v2 verwenden, das das Debuggen vereinfacht und Ihren Code sauberer macht.
2. Organisieren und strukturieren Sie Ihre Hooks
Einer der Vorteile von React Hooks ist die Möglichkeit, weniger Code zu schreiben, der einfach zu lesen ist. In einigen Fällen kann die Menge an useEffect()
und useState()
immer noch verwirrend sein. Wenn Sie Ihre Komponente organisiert halten, trägt dies zur Lesbarkeit bei und hält den Fluss Ihrer Komponenten konsistent und vorhersehbar. Wenn Ihre benutzerdefinierten Hooks zu kompliziert sind, können Sie sie jederzeit in untergeordnete benutzerdefinierte Hooks aufteilen. Extrahieren Sie die Logik Ihrer Komponente in benutzerdefinierte Hooks, um Ihren Code lesbar zu machen.
3. Verwenden Sie React Hooks Snippets
React Hooks Snippets ist eine Visual Studio Code-Erweiterung, um React Hooks einfacher und schneller zu machen. Derzeit werden fünf Hooks unterstützt:
-
useState()
-
useEffect()
-
useContext()
-
useCallback()
-
useMemo()
Andere Snippets wurden ebenfalls hinzugefügt. Ich habe versucht, mit diesen Hooks zu arbeiten, und es war eine der besten Methoden, die ich persönlich bei der Arbeit mit ihnen angewendet habe.
Es gibt zwei Möglichkeiten, wie Sie React Hooks-Snippets zu Ihrem Projekt hinzufügen können:
- Befehl
Starten Sie VS Code Quick Open ( Strg + P ), fügenext install ALDuncanson.react-hooks-snippets
und drücken Sie die Eingabetaste . - Marktplatz für Erweiterungen
Starten Sie „VS Code Extension Marketplace“ ( Strg + Umschalt + X ) und suchen Sie nach „React Hook Snippets“. Suchen Sie dann nach dem Symbol „Alduncanson“.
Ich empfehle den ersten Ausschnitt. Lesen Sie hier mehr über die Snippets oder suchen Sie hier nach den neuesten Hooks-Snippets.
4. Hooks-Regeln berücksichtigen
Bemühen Sie sich, bei der Arbeit mit React Hooks immer die zwei Regeln von Hooks zu berücksichtigen, die wir zuvor gelernt haben.
- Rufen Sie Ihre Hooks nur auf der obersten Ebene an. Rufen Sie Hooks nicht innerhalb von Schleifen, Bedingungen oder verschachtelten Funktionen auf.
- Rufen Sie Hooks immer von React-Funktionskomponenten oder von benutzerdefinierten Hooks auf, rufen Sie keine Hooks von regulären JavaScript-Funktionen auf.
Das ESlint-Plugin namens eslint-plugin-react-hooks
erzwingt diese beiden Regeln. Sie können dieses Plugin zu Ihrem Projekt hinzufügen, wenn Sie möchten, wie wir es oben im Abschnitt Regeln der Hooks erklären.
Best Practices wurden noch nicht vollständig geklärt, da Hooks noch relativ neu sind. Daher sollte die Übernahme mit Vorsicht erfolgen, die man bei der Übernahme einer frühen Technologie treffen würde. In diesem Sinne sind Hooks der Weg für die Zukunft von React.
Fazit
Ich hoffe, Ihnen hat dieses Tutorial gefallen. Wir haben die zwei wichtigsten Regeln von React Hooks gelernt und wie man effektiv in Hooks denkt. Wir haben uns funktionale Komponenten und einige Best Practices angesehen, um Hooks richtig und effektiv zu schreiben. So kurz die Regeln auch sind, es ist wichtig, sie beim Schreiben von Regeln zu Ihrem Leitkompass zu machen. Wenn Sie dazu neigen, es zu vergessen, können Sie das ESLint-Plugin verwenden, um es zu erzwingen.
Ich hoffe, Sie werden alle hier gelernten Lektionen in Ihrem nächsten React-Projekt nutzen. Viel Glück!
Ressourcen
- „Einführung in Hooks“, React Docs
- „Funktionale vs. Klassenkomponenten in Reaktion“, David Joch, Medium
- „Mixins gelten als schädlich“, Dan Abramov, React Blog
- „React Hooks: Best Practices und eine veränderte Denkweise“, Bryan Manuele, Medium
- „Hooks-Snippets für VS-Code reagieren“, Anthony Davis, Visual Code Marketplace