Как реализовать кастомный хук для отслеживания первого рендера в React?
Что проверяют
Знаете ли вы правила работы с useRef и поведение эффектов в StrictMode. Сначала стоит уточнить, зачем нужен флаг: чаще всего настоящая задача звучит как «пропустить эффект при монтировании и выполнять его только на обновлениях». Следом спрашивают, почему ваш хук ведёт себя иначе в режиме разработки.
Как отвечать
Разведите два сценария.
Если флаг нужен внутри эффекта, храните его в useRef и читайте там же:
useRef(true): переживает ререндеры и не вызывает новый рендер при изменении;- пропуск первого запуска: в эффекте проверяете
ref.current, приtrueставитеfalseи выходите, иначе выполняете полезную работу. Так устроен типичныйuseUpdateEffect(effect, deps); - StrictMode: в разработке React монтирует компонент, размонтирует и монтирует снова, эффекты срабатывают дважды. Без сброса флага второй запуск примет монтирование за обновление. Лечится отдельным эффектом с пустыми зависимостями, чей cleanup снова ставит
ref.current = true.
Если флаг нужен в разметке, ref не подходит: документация React запрещает читать и писать ref.current во время рендера, кроме ленивой инициализации. Для отображения используйте состояние: useState(true) и setIsFirst(false) в эффекте. Это стоит одного лишнего рендера, зато результат предсказуем в конкурентном рендеринге.
Для полноты скажите, что «первый рендер» относится к конкретному экземпляру компонента. После размонтирования и повторного появления, например при смене key, флаг снова будет true, а между перезагрузками страницы он ничего не помнит.
Где спотыкаются
Возвращают isFirstRender.current прямо из хука и выводят в JSX. Эффект меняет ref, но ререндера не вызывает, поэтому надпись обновится только при следующем постороннем рендере, а само чтение ref во время рендера нарушает правила React.
Проверяют хук только в продакшен-сборке и удивляются, что в разработке эффект «на обновление» срабатывает сразу после монтирования. Причина в двойном запуске эффектов StrictMode, и отключать StrictMode не выход.
Путают первый рендер компонента с первым визитом пользователя. Для приветствия новичка нужен localStorage или сервер, хук тут ни при чём.