Можно ли реализовать логику без useEffect в React и как?
Что проверяют
Понимаете ли вы, что useEffect нужен для синхронизации с внешними системами, а не для любой логики «после рендера». Следом обычно дают код с эффектом, который пересчитывает состояние из пропсов, и просят его убрать.
Как отвечать
Да, и в большинстве случаев так и нужно. Документация React разбирает это в статье «You Might Not Need an Effect». Главные замены:
- вычисление при рендере: производные данные (отфильтрованный список, полное имя) считаются прямо в теле компонента, без пары
useStateиuseEffect. Дорогое вычисление оборачивают вuseMemo; - обработчики событий: отправка формы, запрос по клику, аналитика действия пишутся в
onClickилиonSubmit. Эффект нужен только для того, что должно произойти из-за самого факта показа компонента; - сброс состояния через
key: чтобы форма очистилась при смене пользователя, передайтеkey={userId}, и React пересоздаст компонент; - внешние подписки:
useSyncExternalStoreдля сторов и браузерных API вродеnavigator.onLine; - загрузка данных: серверные компоненты, TanStack Query или SWR, а в React 19
use()с промисом внутриSuspense. Промис при этом создают вне рендера, иначе на каждый рендер он будет новым; - формы:
useActionStateи actions в React 19 заменяют ручную связку состояния загрузки с эффектом.
Эффект остаётся правильным инструментом для подписки на WebSocket, работы со сторонней DOM-библиотекой, таймеров и всего, что требует очистки при размонтировании.
Где спотыкаются
Предлагают классовые компоненты с componentDidMount. Это тот же эффект в другом синтаксисе, и в новом коде классы не пишут.
Держат производные данные в состоянии и синхронизируют их эффектом. Получается лишний рендер с устаревшим значением и цепочки эффектов, которые запускают друг друга.
Считают двойной запуск эффекта в Strict Mode багом React и глушат его флагом в useRef. Двойной запуск в режиме разработки как раз показывает, что у эффекта нет корректной очистки.