Чем отличаются состояния useEffect и какие переходы между ними возможны?
Хуки
У эффекта нет «состояний» в смысле state, но есть чёткий жизненный цикл: не запущен → запущен (активен) → очищен, с повторами по зависимостям.
Фазы эффекта
Создан, но не выполнен. Компонент отрендерился, коммит прошёл — эффект стоит в очереди (для useEffect — после отрисовки кадра, для useLayoutEffect — до неё).
Активен. Колбэк выполнился: подписка установлена, запрос отправлен, таймер идёт. React запомнил cleanup-функцию, если она возвращена.
Очищен. Cleanup выполнен. Происходит в двух случаях: перед повторным запуском (изменились deps) и при размонтировании.
Возможные переходы
рендер+коммит → [активен] --deps изменились--> [очищен] → [активен снова]
└------- размонтирование --> [очищен] (конец)- активен → очищен → активен: пересинхронизация (сменился roomId — отключились от старой комнаты, подключились к новой).
- активен → очищен: размонтирование, финал.
- активен → активен без очистки — невозможно: React всегда чистит предыдущий эффект перед новым запуском.
- Эффект без deps проходит цикл «очищен → активен» после каждого рендера; с
[]— ровно один раз (плюс двойной прогон в dev StrictMode).
Практический смысл
Эта модель объясняет, почему эффект — не «событие монтирования», а синхронизация: он описывает состояние связи с внешней системой, а React переводит эффект между «активен» и «очищен», когда данные меняются.
Коротко для собеседования
Эффект живёт в цикле «запущен → очищен → запущен»: cleanup выполняется перед каждым перезапуском (изменение deps) и при размонтировании; два активных состояния подряд без очистки невозможны. Без deps цикл повторяется каждый рендер, с [] — однократно (в dev StrictMode дублируется). Это модель синхронизации, а не событий жизненного цикла.