Правила хуков¶
Хуки — нововведение в React 16.8, которое позволяет использовать состояние и другие возможности React без написания классов.
Хуки — обычные JavaScript-функции, но существует два правила, которым нужно следовать. Чтобы автоматически их применять мы создали плагин для линтера:
Используйте хуки только на верхнем уровне¶
Не используйте хуки внутри циклов, условных операторов или вложенных функций Вместо этого всегда используйте хуки только на верхнем уровне React-функций. Исполнение этого правила гарантирует, что хуки вызываются в одинаковой последовательности при каждом рендере компонента. Это позволит React правильно сохранять состояние хуков между множественными вызовами useState
и useEffect
. (Если вам интересно, подробное объяснение ниже.)
Вызывайте хуки только из React-функций¶
Не вызывайте хуки из обычных функций JavaScript. Вместо этого можно:
- ✅ Вызывать хуки из функционального компонента React.
- ✅ Вызывать хуки из пользовательского хука (мы научимся делать это на следующей странице).
Следуя этому правилу, можно гарантировать, что вся логика состояния компонента чётко видна из исходного кода.
Плагин для ESLint¶
Мы выпустили плагин для ESLint eslint-plugin-react-hooks
, который принуждает к соблюдению этих двух правил. Если хотите испытать его в деле, добавьте этот плагин в ваш проект.
1 |
|
1 2 3 4 5 6 7 8 9 10 11 12 |
|
В будущем мы намереваемся включать этот плагин в Create React App и подобные инструменты по умолчанию.
Вы можете пропустить остаток этой страницы и перейти к созданию собственного хука. Но если вам интересно, ниже приведено объяснение, почему правила хуков необходимы.
Объяснение¶
Как мы ранее узнали хуки состояния или эффектов в одном и том же компоненте можно использовать многократно:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
Итак, как же React сопоставляет переменные состояния с вызовами useState
? Ответ таков: React полагается на порядок вызова хуков. Наш пример работает, потому что порядок вызова хуков одинаков при каждом рендере.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
До тех пор пока порядок вызова хуков одинаков в каждом рендере, React может сопоставить некое внутреннее состояние с каждым из них. Но что случится, если мы поместим вызов хука (например, эффект persistForm
) внутрь условного оператора?
1 2 3 4 5 6 |
|
Условие name !== ''
равняется true
при первом рендере, поэтому хук выполняется. Тем не менее, при следующем рендере пользователь может обратить это условие в false
, очистив поля формы. Теперь во время рендера хук будет пропущен и порядок вызовов хуков изменится.
1 2 3 4 |
|
React не будет знать, что вернуть для второго вызова хука useState
. React ожидал, что второй вызов хука в этом компоненте соответствует эффекту persistForm
, так же как при предыдущем рендере, но это больше не так. Начиная с этого момента, вызов каждого хука, следующего за пропущенным, также будет сдвинут на один назад, что приведёт к ошибкам.
Вот почему хуки должны вызываться на верхнем уровне компонента. Если мы хотим запускать эффект по условию, то можем поместить это условие внутрь хука:
1 2 3 4 5 6 |
|
Эта проблема не будет вас беспокоить, если вы включите в свой проект наше правило линтера. Но теперь вы знаете, почему хуки работают таким образом и какие проблемы это правило предотвращает.
Следующие шаги¶
Наконец-то мы готовы изучить как написать свой собственный хук! Пользовательские хуки позволят вам включить собственные хуки React в ваши абстракции и повторно использовать общую логику состояния в различных компонентах.