React Strict Mode: зачем он нужен
Подробно разбираем React Strict Mode: какие проверки он включает, почему в dev все «вызывается дважды», какие баги ловит и как безопасно внедрять в production-командах.
- Введение
- Что такое Strict Mode и какую задачу он решает
- Короткий ответ
- Что он не делает
- Что он реально дает команде
- Архитектура: как Strict Mode встроен в жизненный цикл
- Почему в Strict Mode кажется, что «все вызывается дважды»
- Практический пример: неидемпотентный эффект
- Таблица сравнения: Strict Mode и соседние инструменты
- Production pitfalls: где команды чаще ошибаются со Strict Mode
- Ошибка 1. Отключить Strict Mode при первых «дублях»
- Ошибка 2. Делать сетевой запрос «на mount любой ценой»
- Ошибка 3. Побочные эффекты во время рендера
- Ошибка 4. Неучтенный re-run тяжёлой инициализации
- Разбор производительности
- Когда Strict Mode не покрывает все риски
- Практики, которые работают в командах
- Частые ошибки
- Как отвечать на интервью про Strict Mode
- Практический кейс из production: защита от дублей запросов в Strict Mode
- Чек-лист внедрения Strict Mode в существующий проект
- FAQ
- Strict Mode нужно включать на весь проект сразу?
- Двойной useEffect в dev — это нормально?
- Можно ли отключить Strict Mode только для части дерева?
- Strict Mode заменяет тесты?
- Почему после включения Strict Mode сломалась аналитика?
- Итоги
Введение
React Strict Mode часто воспринимают как «режим, где все ломается и вызывается по два раза». Такая реакция понятна: при первом включении команда видит дубли логов, повторные вызовы эффектов и нестабильные тесты, которые до этого казались «зелеными».
Но Strict Mode не ломает приложение ради эксперимента. Он делает видимыми проблемы, которые уже есть в коде: неидемпотентные эффекты, пропущенный cleanup, зависимости с побочными эффектами, старые API-подходы. В production эти дефекты обычно проявляются позже и дороже: под нагрузкой, в сложной навигации или после большого рефакторинга.
Если вы хотите связать тему с общим жизненным циклом рендера, полезно также ознакомиться с разбор жизненного цикла React-компонента, материал про batching обновлений и объяснение concurrent rendering.
В статье разберем, что именно проверяет Strict Mode, почему появляются «двойные» эффекты в dev, как диагностировать реальные баги и как внедрять режим поэтапно в существующем проекте.
Больше вопросов в Telegram
Ежедневные разборы и реальные кейсы с интервью.
Что такое Strict Mode и какую задачу он решает
Короткий ответ
<StrictMode> — это специальный режим React для разработки, который включает дополнительные проверки и помогает находить потенциально опасный код до релиза.
Что он не делает
- не является фичей «ускорения»;
- не должен менять production-поведение;
- не решает архитектуру автоматически.
Что он реально дает команде
- раннее выявление неочевидных побочных эффектов;
- проверку корректного cleanup в эффектах;
- сигнал о рисковых паттернах, плохо совместимых с современным React.
Ключевая мысль: Strict Mode увеличивает количество диагностических сообщений в dev, чтобы уменьшить стоимость ошибок в production.
Архитектура: как Strict Mode встроен в жизненный цикл
В обычном dev-потоке React выполняет рендер, commit и эффекты. В Strict Mode для части сценариев React намеренно добавляет дополнительную проверочную фазу: симулирует повторное выполнение рендера и жизненного цикла эффекта (setup/cleanup/setup).
Упрощенно это выглядит так:
- Компонент монтируется.
- Эффект выполняет setup.
- React выполняет cleanup.
- React повторно выполняет setup.
Зачем это нужно:
- проверить, что эффект корректно очищает ресурсы;
- убедиться, что setup не содержит необратимых действий;
- поймать скрытые утечки подписок, таймеров и соединений.
Границы ответственности:
- Strict Mode выявляет проблемы;
- разработчик исправляет поток побочных эффектов;
- тесты фиксируют ожидаемое поведение.
Типичная точка отказа: команда видит повторный сетевой запрос в dev и «чинит» это выключением Strict Mode, вместо того чтобы сделать эффект идемпотентным или вынести триггер в пользовательское действие.
Почему в Strict Mode кажется, что «все вызывается дважды»
Главная причина — специальное поведение в dev-режиме, направленное на обнаружение небезопасных side эффектов. Это не баг React, а инструмент диагностики.
Чаще всего разработчики замечают:
- двойной лог в теле компонента;
- повтор setup у
useEffect; - повторную инициализацию внешнего ресурса без cleanup.
Важно: двойной вызов в dev не равен двойному вызову в production. Но если код в dev ломается, это уже сигнал, что в нем есть хрупкая логика, которая может проявиться и в боевых сценариях (например, при быстрых mount/unmount переходах).
Практический пример: неидемпотентный эффект
function ChatRoom({ roomId }: { roomId: string }) {
useEffect(() => {
const connection = createConnection(roomId);
connection.connect();
return () => {
connection.disconnect();
};
}, [roomId]);
return <p>Room: {roomId}</p>;
}
В Strict Mode этот код безопасен: setup повторится, но cleanup между вызовами корректно закроет соединение.
Проблемный вариант:
function ChatRoomBroken({ roomId }: { roomId: string }) {
useEffect(() => {
// Подключаемся, но забываем cleanup.
createConnection(roomId).connect();
}, [roomId]);
return <p>Room: {roomId}</p>;
}
Здесь Strict Mode быстро покажет дефект: повторные подключения и утечки. Без него баг может долго скрываться.
Таблица сравнения: Strict Mode и соседние инструменты
| Критерий | Strict Mode | ESLint React Hooks Rules | Unit/Integration tests | Runtime monitoring |
|---|---|---|---|---|
| Когда работает | Dev runtime | Статический анализ | Во время тестов | На тестовых окружениях после деплоя |
| Что ловит лучше всего | Неидемпотентные эффекты, плохой cleanup | Ошибки зависимостей и паттернов хуков | Регрессии сценариев | Инциденты и деградации в реальном трафике |
| Ловит проблемы side effects в динамике | Да | Частично | Частично | Да |
| Цена внедрения | Низкая/средняя | Низкая | Средняя | Средняя/высокая |
| Риск ложных интерпретаций | Средний («в dev все дважды») | Низкий | Средний | Средний |
| Заменяет другие инструменты | Нет | Нет | Нет | Нет |
Strict Mode эффективен как часть системы качества, а не как отдельная серебряная пуля.
Production pitfalls: где команды чаще ошибаются со Strict Mode
Ошибка 1. Отключить Strict Mode при первых «дублях»
Симптомы:
- в репозитории появляется комментарий «иначе дергается два раза»;
- проблемы cleanup остаются нераскрытыми;
- баги попадают в production через несколько спринтов.
Последствие: технический долг растет, а диагностика сдвигается вправо.
Профилактика: чинить причину дубля, а не скрывать симптом.
Ошибка 2. Делать сетевой запрос «на mount любой ценой»
Симптомы:
- запросы стартуют повторно без отмены;
- race condition при быстрых переходах между экранами;
- результаты старого запроса перезаписываются более новыми.
Последствие: нестабильный интерфейс, лишняя нагрузка на API.
Профилактика: использовать отмену (AbortController), маркер актуальности запроса и корректный cleanup.
Ошибка 3. Побочные эффекты во время рендера
Симптомы:
- неожиданные мутации глобального состояния;
- дубли событий аналитики;
- сложно воспроизвести порядок вызовов.
Последствие: флейки-тесты и непредсказуемое поведение.
Профилактика: побочные действия только в эффектах/обработчиках событий, а рендер держать чистым.
Ошибка 4. Неучтенный re-run тяжёлой инициализации
Симптомы:
- резкий рост времени dev-рендера;
- перегрев local environment на сложных страницах;
- команда отключает проверки «потому что медленно».
Последствие: ухудшается качество обратной связи в разработке.
Профилактика: выделить тяжелую часть в ленивую инициализацию, мемоизацию по месту и разделение ответственности компонентов.
Разбор производительности
Strict Mode может визуально «замедлить» dev, потому что выполняет больше проверок. Это ожидаемо. Главный вопрос не «почему dev стал тяжелее», а «какие ошибки это помогло найти раньше».
Когда Strict Mode полезен для производительности в долгую:
- выявляет неочищенные подписки и интервалы;
- обнаруживает эффекты, вызывающие каскад лишних ререндеров;
- заставляет код быть устойчивым к повторным mount/unmount сценариям.
Когда он не решит проблему:
- узкое место в network latency;
- тяжелая бизнес-функция блокирует main thread;
- архитектура экрана монолитна и не разделена по ответственности.
Практический подход:
- Профилируйте dev-проблемы отдельно от production-метрик.
- После фикса эффекта проверяйте рендеры и commit time в React Profiler.
- Не делайте выводы о production-FPS только на основании «двойных» вызовов Strict Mode.
Прокачай React за 7 дней
20 вопросов и разборов по React Hooks.
Когда Strict Mode не покрывает все риски
Strict Mode не проверяет бизнес-валидность данных и не заменяет тестирование end-to-end. Он также не поймает часть проблем, которые проявляются только при реальном трафике, медленной сети и состояниях гонки между клиентом и сервером.
Поэтому минимальный стек контроля качества обычно такой:
- Strict Mode в dev;
- линтеры и правила хуков;
- тесты ключевых сценариев;
- мониторинг ошибок и пользовательских метрик в production.
Практики, которые работают в командах
- Включать Strict Mode по умолчанию в новых модулях.
- Для legacy-кода внедрять поэтапно: экран за экраном, с фиксами cleanup.
- На code review требовать идемпотентность эффектов и явный teardown ресурсов.
- Разделять инициализацию ресурса и реакцию на действие пользователя, чтобы избежать смешения разных причин запуска эффектов.
- Покрывать тестами сценарии быстрой смены props и unmount во время async.
- Для рискованных рефакторингов использовать feature flag и заранее готовить rollback.
Частые ошибки
- Считать, что Strict Mode «ломает React».
- Дублировать analytics-события из-за эффектов без защиты от повторного setup.
- Хранить внешние экземпляры (подключения) без destroy/disconnect в cleanup.
- Блокировать main thread тяжелыми вычислениями при каждом mount.
- Отключать Strict Mode глобально вместо локального исправления проблемного компонента.
Как отвечать на интервью про Strict Mode
Короткий рабочий шаблон:
- Strict Mode — dev-инструмент для поиска небезопасных побочных эффектов и устаревших паттернов.
- В dev он может повторно запускать рендер/эффектные сценарии, чтобы проверить cleanup и идемпотентность.
- На production-сборку эти проверки напрямую не переносятся.
- Если Strict Mode выявил дубль запроса, это сигнал к исправлению эффекта, а не к отключению режима.
Такой ответ показывает, что вы понимаете эксплуатационную ценность инструмента, а не только формальное определение.
Подготовься к React-собеседованию на реальных кейсах
Разберем Strict Mode, эффекты и рендеринг на практических задачах с обратной связью.
Практический кейс из production: защита от дублей запросов в Strict Mode
Сценарий: страница профиля загружает данные пользователя при userId и часто перемонтируется при навигации. В dev Strict Mode видно двойной запуск эффекта, а часть ответов приходит в разном порядке.
Надежный подход:
function UserProfile({ userId }: { userId: string }) {
const [data, setData] = useState<{ name: string } | null>(null);
const [loading, setLoading] = useState(false);
const requestIdRef = useRef(0);
useEffect(() => {
const controller = new AbortController();
const currentRequestId = ++requestIdRef.current;
setLoading(true);
fetch(`/api/user/${userId}`, { signal: controller.signal })
.then((r) => r.json())
.then((payload) => {
if (currentRequestId === requestIdRef.current) {
setData(payload);
}
})
.catch((err: unknown) => {
if ((err as { name?: string }).name !== "AbortError") {
if (currentRequestId === requestIdRef.current) {
setData(null);
}
}
})
.finally(() => {
if (currentRequestId === requestIdRef.current) {
setLoading(false);
}
});
return () => controller.abort();
}, [userId]);
if (loading) return <p>Загрузка...</p>;
if (!data) return <p>Нет данных</p>;
return <h2>{data.name}</h2>;
}
Почему это работает:
- cleanup отменяет предыдущий запрос;
requestIdRefзащищает от устаревших ответов;- UI-состояние остается в
useState, а технический маркер — вuseRef.
Такой паттерн устойчив и в Strict Mode, и в реальных race-сценариях production.
Чек-лист внедрения Strict Mode в существующий проект
-
Есть ли компоненты с побочными эффектами без cleanup? Если да, начать с них: таймеры, подписки, sockets, observers.
-
Есть ли сетевые эффекты без отмены/защиты от гонок? Добавить
AbortControllerи маркер актуального запроса. -
Есть ли побочные действия во время рендера? Вынести их в эффект или обработчик события.
-
Есть ли тяжелые mount-инициализации? Разделить ответственность компонента и оптимизировать горячий путь.
-
Есть ли тесты на быстрый mount/unmount и смену props? Без таких тестов регрессии возвращаются после первого же рефакторинга.
Этот чек-лист помогает включать Strict Mode без хаоса и без массовых «временных» отключений.
FAQ
Strict Mode нужно включать на весь проект сразу?
Не обязательно. В legacy-проектах безопаснее идти поэтапно, начиная с модулей с высоким риском side effects.
Двойной useEffect в dev — это нормально?
Да, для Strict Mode это ожидаемый диагностический сценарий. Важнее проверить, что cleanup корректный.
Можно ли отключить Strict Mode только для части дерева?
Да. Обычно так и делают в миграции: проблемный участок временно изолируют, а затем приводят к корректному поведению.
Strict Mode заменяет тесты?
Нет. Он выявляет отдельный класс ошибок во время разработки, но не покрывает бизнес-сценарии end-to-end.
Почему после включения Strict Mode сломалась аналитика?
Чаще всего события отправляются из неидемпотентного эффекта. Нужно исправить место отправки и добавить защиту от дублей.
Итоги
Strict Mode нужен не для «строгости ради строгости», а для ранней диагностики багов, которые дорого исправлять на поздних этапах. Он поднимает инженерную дисциплину: эффекты становятся чище, cleanup явнее, а код устойчивее к сложным сценариям рендера.
Оптимальная стратегия в командах: не выключать режим из-за шума, а последовательно исправлять причины. Тогда Strict Mode становится не раздражителем, а реальным инструментом снижения production-рисков.
Если хотите углубиться дальше, изучите практику с useEffect и сложными вопросами, разбор React Hooks для интервью и ошибки оптимизации компонентов.
Больше вопросов в Telegram
Ежедневные разборы и реальные кейсы с интервью.
Автор
Lexicon Team
Читайте также
frontend
Почему useEffect вызывает баги: разбор типичных ошибок и безопасных альтернатив
Разбираем, почему useEffect часто становится источником багов в React: stale closure, лишние зависимости, гонки запросов, Strict Mode, утечки подписок и случаи, когда эффект вообще не нужен.
frontend
React и TypeScript: частые вопросы на интервью
Разбираем частые вопросы на интервью по React и TypeScript: типизация props, hooks, events, generics, refs, discriminated unions. А также типичные ошибки кандидатов и примеры сильных ответов.
frontend
Почему React может рендерить дважды в dev режиме: Strict Mode без мифов
Разбираем, почему React в режиме разработки может вызывать рендер и эффекты дважды, какие баги это выявляет, как отличать норму от дефекта и как отвечать на собеседовании.