Die Regeln für Hooks
Noch ein Hook von dir: useFetch(url) lädt eine Datei, wie es die Effekte in der Lektion über Effekte getan haben, und gibt ein Objekt mit drei Werten zurück, { daten, laedt, fehler }. Programm.jsx benutzt ihn schon: Es zeigt Programm wird geladen…, den Fehler oder die Bands. Vorerst hat useFetch.js aber nur die drei States, und es wird nichts geladen.
Bevor du ihn fertigstellst, hier die Regeln, die jeder Hook befolgt, die von React und deine eigenen:
- Rufe Hooks nur auf der obersten Ebene auf einer Komponente oder deines eigenen Hooks: nicht in einem
if, in einer Schleife, in einem Handler oder in einer anderen Funktion. Rufe sie bei jedem Rendern der Komponente auf, in derselben Reihenfolge. - Rufe Hooks nur aus Komponenten und aus anderen Hooks auf, nie aus gewöhnlichen Funktionen.
- Die Namen von Hooks beginnen mit
use. So erkennen React und andere Werkzeuge, dass eine Funktion ein Hook ist und die Regeln für sie gelten.
Warum die Reihenfolge? React kennt die States einer Komponente nicht an ihren Namen. Es weiß nur, dass die Komponente zuerst, zweitens und drittens useState aufgerufen hat, und merkt sich ihre Werte in dieser Reihenfolge von einem Rendern zum nächsten. Wird ein Hook nur manchmal aufgerufen, ändert sich die Reihenfolge, und React kann nicht mehr sagen, welcher Wert wohin gehört. Dann bricht es mit einem Fehler ab.
Genau das passiert in Neuigkeiten.jsx. Solange die Neuigkeiten nicht geöffnet sind, kehrt die Komponente nach einem Hook vorzeitig zurück. Sind sie geöffnet, kommt sie weiter und ruft auch useFetch auf, das drei weitere Hooks hat. Klicke auf Neuigkeiten anzeigen, und die ganze Seite verschwindet. Die Konsole sagt, warum:
React has detected a change in the order of Hooks called by Neuigkeiten. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: https://react.dev/link/rules-of-hooks
Previous render Next render
------------------------------------------------------
1. useState useState
2. undefined useState
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error: Rendered more hooks than during the previous render.
at useFetch (useFetch.js:4)Die Tabelle vergleicht die beiden Renderdurchgänge von Neuigkeiten: Im vorherigen gab es keinen zweiten Hook (undefined), im aktuellen ist da ein useState. Der Fehler nennt dann die Zeile, in der React es bemerkt hat: das erste useState in useFetch.
Die Lösung: Rufe zuerst alle Hooks auf und kehre erst danach vorzeitig zurück. Wenn ein Effekt nur manchmal etwas tun soll, setze das if in den Effekt, nicht um ihn herum.
So schreibst du es:
Anweisungen
- 1
Vervollständige
useFetch: Füge einen Effekt hinzu, derurllädt, wie in der Lektion über Effekte. Er setztlaedtauftrueundfehlerauf"", lädt die Datei, legt das Gelesene indatenund setztlaedtauffalse. Ist die Antwort nicht OK, legt er stattdessenDie Daten konnten nicht geladen werden.infehlerund setzt auch dannlaedtauffalse. Der Effekt verwendeturl, seine Abhängigkeiten sind also[url]. Dann zeigt das Programm die Bands. - 2
Repariere
Neuigkeiten.jsx: Verschiebe die Zeile mituseFetchüber dasif, unteruseState, damit die Komponente bei jedem Rendern beide Hooks aufruft. Dann zeigt Neuigkeiten anzeigen die drei Meldungen. Sie sind sogar schon vor dem Klick bereit: Die Komponente lädt sie jetzt sofort.