Правила хуков
Ещё один собственный хук: useFetch(url) загружает файл, как это делали эффекты в уроке про эффекты, и возвращает объект с тремя значениями, { data, loading, error }. Lineup.jsx его уже использует: он показывает Загружаем программу…, ошибку или группы. Пока же в useFetch.js есть только три состояния, и ничего не загружается.
Прежде чем вы его допишете, вот правила, которым подчиняется каждый хук, и React, и ваш:
- Вызывайте хуки только на верхнем уровне компонента или собственного хука: не внутри
if, цикла, обработчика или другой функции. Вызывайте их при каждой отрисовке компонента и в одном и том же порядке. - Вызывайте хуки только из компонентов и из других хуков, никогда из обычных функций.
- Имена хуков начинаются с
use. По этому React и другие инструменты понимают, что функция — хук и что к ней применяются правила.
Почему важен порядок? React не знает состояния компонента по именам. Он знает только, что компонент вызвал useState первым, вторым, третьим, и хранит их значения в этом порядке от одной отрисовки к другой. Если хук вызывается лишь иногда, порядок меняется, и React не может понять, какое значение чему принадлежит. Поэтому он останавливается с ошибкой.
Именно это происходит в News.jsx. Пока новости не открыты, компонент делает ранний возврат после одного хука. Когда они открыты, он идёт дальше и вызывает ещё и useFetch, а в нём ещё три хука. Нажмите «Показать новости» — и вся страница исчезнет. Почему так, объясняет консоль:
React has detected a change in the order of Hooks called by News. 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)Таблица сравнивает две отрисовки News: в предыдущей второго хука не было (undefined), а в этой есть useState. Затем ошибка называет строку, где React это заметил: первый useState в useFetch.
Как исправить: сначала вызовите все хуки, и только потом делайте ранний возврат. Если эффект должен работать лишь иногда, поместите if внутрь эффекта, а не вокруг него.
Задание
- 1
Допишите
useFetch: добавьте эффект, который загружаетurl, как в уроке про эффекты. Он записывает вloadingзначениеtrue, а вerror—"", загружает файл, кладёт прочитанное вdataи записывает вloadingзначениеfalse. Если ответ не OK, он вместо этого кладёт вerrorтекстНе удалось загрузить данные.и тоже записывает вloadingзначениеfalse. Эффект используетurl, поэтому его зависимости —[url]. После этого программа покажет группы. - 2
Исправьте
News.jsx: перенесите строку сuseFetchвышеif, подuseState, чтобы компонент вызывал оба хука при каждой отрисовке. Тогда «Показать новости» покажет три новости. Они даже готовы до клика: теперь компонент загружает их сразу.