Собеседования

Вопросы на собеседовании по React: что спрашивают и как отвечать

Разбираем темы, которые встречаются почти на каждом техническом интервью frontend-разработчика: рендеринг, хуки, состояние, производительность и Next.js.

На собеседовании по React чаще всего спрашивают о том, как происходит рендеринг и reconciliation, о правилах хуков и массиве зависимостей useEffect, о мемоизации, управлении состоянием, производительности и - для позиций уровня middle - о Next.js и серверном рендеринге. Интервьюер проверяет не определения, а понимание механизма: почему React работает именно так и как вы применяли это в проектах.

Вопросы по React повторяются из компании в компанию. Хорошая новость: их можно подготовить. Плохая: заученное определение распознаётся сразу, стоит задать один уточняющий вопрос. Ниже - ключевые темы, типичные формулировки и то, что за ними хотят услышать.

Рендеринг и reconciliation

Что происходит, когда меняется состояние компонента

Хороший ответ: React планирует повторный рендер, вызывает функцию компонента заново, получает новое дерево элементов, сравнивает его с предыдущим и применяет к DOM только разницу. Сравнение и есть reconciliation. Важно упомянуть, что при рендере родителя по умолчанию перерисовываются и все дочерние компоненты - даже если их пропсы не изменились.

Рендер и коммит

Сильный кандидат разделяет две фазы. В фазе рендера React вызывает компоненты и вычисляет, что должно измениться, - эта фаза может прерываться и повторяться. В фазе коммита изменения применяются к DOM, после чего запускаются эффекты. Отсюда вывод: функция компонента должна быть чистой, без побочных эффектов.

Ключи в списках

Ключ помогает сопоставить элементы между рендерами. Если использовать индекс массива, при вставке элемента в начало списка React решит, что изменились все элементы, и состояние полей ввода «переедет» к соседям. Ключ должен быть стабильным идентификатором из данных.

Батчинг обновлений

Несколько вызовов setState в одном обработчике объединяются в один рендер. Начиная с React 18 это работает и в промисах, и в таймерах. Отсюда частый вопрос с подвохом: почему после setState значение состояния в той же функции ещё старое. Ответ: состояние обновится при следующем рендере, а для вычисления от предыдущего значения нужна функциональная форма обновления.

Хуки и их правила

Почему хуки нельзя вызывать в условиях и циклах

React хранит состояние хуков по порядку их вызова. Если порядок меняется между рендерами, состояние «съезжает» к другому хуку. Поэтому хуки вызываются только на верхнем уровне компонента или другого хука. Линтер eslint-plugin-react-hooks проверяет это автоматически.

useEffect и массив зависимостей

Нужно понимать, когда эффект запускается, зачем функция очистки и почему в зависимости попадает всё, что используется внутри. Функция очистки вызывается перед следующим запуском эффекта и при размонтировании - в ней отписываются от событий, отменяют таймеры и запросы. Бонус - объяснить, что многие эффекты не нужны вовсе: производные данные лучше вычислять при рендере, а реакцию на действие пользователя - писать в обработчике события.

Почему эффект срабатывает дважды

В режиме разработки со StrictMode React намеренно монтирует, размонтирует и снова монтирует компонент, чтобы выявить эффекты без корректной очистки. В продакшене такого нет. Правильный ответ - не отключать StrictMode, а написать очистку так, чтобы повторный запуск был безопасен.

useMemo и useCallback

Оба мемоизируют между рендерами: useMemo - значение, useCallback - функцию. Хороший ответ включает, когда это имеет смысл (дорогие вычисления, стабильные ссылки для React.memo и зависимостей эффектов) и когда только добавляет сложности. Мемоизация сама по себе не бесплатна: React хранит значение и сравнивает зависимости на каждом рендере.

useRef

Ref хранит изменяемое значение, которое переживает рендеры и при изменении не вызывает новый рендер. Используется для доступа к DOM-элементам, хранения таймеров, предыдущих значений и любых данных, которые не должны влиять на отображение.

Собственные хуки

Часто просят написать хук: useDebounce, useFetch, useLocalStorage, useOnClickOutside. Проверяют, умеете ли вы вынести логику из компонента, правильно указать зависимости и сделать очистку. Хороший хук имеет понятный интерфейс и не знает ничего о разметке.

Управление состоянием

  • Чем локальное состояние отличается от глобального и когда поднимать состояние выше.
  • Когда хватит Context, а когда нужен Redux Toolkit или Zustand.
  • Почему данные с сервера лучше держать в TanStack Query или RTK Query, а не в глобальном сторе.
  • Зачем хранить фильтры и пагинацию в URL.

Context и лишние рендеры

Когда меняется значение контекста, перерисовываются все его потребители. Если положить в один контекст часто меняющиеся данные и редко меняющиеся настройки, будут перерисовываться лишние компоненты. Решения: разделить контексты, мемоизировать значение провайдера, для частых обновлений использовать стейт-менеджер с подписками на часть состояния.

Серверное и клиентское состояние

Данные с сервера - это кеш чужого состояния: они устаревают, их нужно перезапрашивать, дедуплицировать запросы и обрабатывать ошибки. Библиотеки вроде TanStack Query делают это из коробки. Хранить такие данные в Redux вручную - источник ошибок и лишнего кода. Этот вопрос хорошо показывает, работали ли вы с реальным приложением.

Формы

Спрашивают разницу между контролируемыми и неконтролируемыми компонентами, как организовать валидацию и почему большие формы на контролируемых полях могут тормозить. Хороший ответ упоминает React Hook Form и схемы валидации вроде Zod: форма рендерится реже, а правила валидации описаны в одном месте и переиспользуются.

Производительность

Спрашивают, как найти и устранить лишние рендеры: React Profiler, React.memo, разделение контекстов, виртуализация длинных списков, ленивая загрузка компонентов через lazy и Suspense. Покажите, что сначала измеряете, а потом оптимизируете: преждевременная мемоизация всего подряд - тоже ошибка, и интервьюеры это знают.

  • Как найти компонент, который рендерится слишком часто.
  • Почему объект или функция, созданные в рендере, ломают React.memo у дочернего компонента.
  • Как отрисовать список из десятков тысяч строк без зависаний.
  • Как уменьшить размер бандла: разделение кода, динамический импорт, анализ зависимостей.

Next.js и рендеринг на сервере

Для позиций уровня middle почти всегда спрашивают разницу между SSR, SSG, ISR и CSR и когда что выбирать. SSR генерирует страницу на каждый запрос, SSG - на этапе сборки, ISR пересобирает статические страницы по расписанию или по событию, CSR отдаёт пустую оболочку и рендерит всё в браузере.

В App Router добавляются серверные и клиентские компоненты. Серверные компоненты выполняются только на сервере, могут обращаться к данным напрямую и не попадают в клиентский бандл. Клиентские помечаются директивой use client и нужны там, где есть состояние, эффекты и обработчики событий. Частый вопрос - где провести эту границу и как передать данные с сервера на клиент.

Полезно понимать файловый роутинг, layout и загрузочные состояния, а также встроенные оптимизации изображений и шрифтов.

Тестирование

Спрашивают, что и как вы тестируете: логику в хуках и утилитах - unit-тестами на Jest или Vitest, компоненты - через React Testing Library с проверкой поведения, а не внутренней реализации. Хороший ответ объясняет, почему тест должен искать элементы так, как их видит пользователь, - по роли и тексту, а не по классам.

Обработка ошибок и продвинутые темы

Error boundaries

Ошибка при рендере одного компонента по умолчанию ломает всё приложение. Error boundary перехватывает ошибки в своём поддереве и показывает запасной интерфейс. Важно знать ограничения: границы не ловят ошибки в обработчиках событий и асинхронном коде - их нужно обрабатывать отдельно.

Порталы и передача ref

Портал рендерит элемент в другом месте DOM - например, модальное окно в конце body, - сохраняя его положение в дереве React: события всплывают по дереву компонентов, а контекст доступен. Передача ref в дочерний компонент нужна, когда родителю требуется доступ к DOM-элементу внутри, например чтобы поставить фокус.

Конкурентные возможности

На позицию middle могут спросить про useTransition и useDeferredValue: они позволяют пометить обновление как несрочное, чтобы ввод оставался отзывчивым, пока тяжёлый список перерисовывается. Достаточно понимать идею приоритетов обновлений и уметь привести пример.

React и TypeScript

Всё чаще вопросы по React задают в связке с TypeScript: как типизировать пропсы и children, как описать компонент, принимающий пропсы нативного элемента, как типизировать собственный хук с дженериком, чем тип события изменения поля отличается от события клика. Эти вопросы проверяют, писали ли вы типизированный код в реальном проекте.

Вопросы, которые стоит задать интервьюеру

В конце технического интервью обычно дают возможность задать вопросы. Это тоже часть оценки: вопросы показывают, что вам важно. Спросите, на какой версии React и с каким роутингом работает проект, как организовано управление состоянием, есть ли код-ревью и тесты, как устроен процесс релиза, какие задачи ждут нового разработчика в первые месяцы. Ответы помогут и вам понять, подходит ли команда.

Вопросы для уровня middle: архитектура

На позицию middle всё чаще спрашивают не про отдельные хуки, а про организацию приложения. Как разделить код на слои и фичи, чтобы команда не мешала друг другу. Где проходит граница между компонентами интерфейса и бизнес-логикой. Как организовать работу с API: генерация клиента по схеме, единая обработка ошибок, типизация ответов. Как устроить дизайн-систему и переиспользуемые компоненты. Отвечать на такие вопросы проще всего на примере собственного проекта: какая структура была, какие проблемы она создала и как вы их решили.

Методологии вроде Feature-Sliced Design упоминают часто. Знать их полезно, но важнее объяснить, какую проблему решает выбранный подход: предсказуемые зависимости между модулями, понятное место для нового кода, изоляция фич.

Ещё одна частая тема - доступность интерфейса: семантическая разметка, работа с клавиатуры, подписи для полей и кнопок. Вопросы о ней показывают, думаете ли вы о всех пользователях продукта, а не только о тех, кто пользуется мышью.

Как готовиться к вопросам по React

  1. Составьте список тем из этой статьи и отметьте, по каким можете ответить вслух без подготовки.
  2. Для каждой слабой темы прочитайте раздел официальной документации React - она подробно объясняет механизмы и типичные ошибки.
  3. Напишите небольшой пример для каждой темы: эффект с очисткой, мемоизированный список, собственный хук.
  4. Подготовьте для каждой темы пример из своего проекта.
  5. Проговорите ответы вслух, а лучше пройдите мок-собеседование.

Вопросы с подвохом

  • Можно ли менять состояние напрямую? Нет: React сравнивает ссылки, и мутация объекта не вызовет рендер. Нужно создавать новый объект или массив.
  • Что будет, если не указать массив зависимостей у useEffect? Эффект будет запускаться после каждого рендера.
  • Почему компонент рендерится, хотя пропсы не изменились? Перерисовался родитель, изменился используемый контекст или в пропсы передаётся новый объект на каждом рендере.
  • Зачем нужен Fragment? Чтобы вернуть несколько элементов без лишней обёртки в DOM.
  • Чем отличаются пропсы и состояние? Пропсы приходят от родителя и не меняются компонентом, состояние принадлежит компоненту и меняется через сеттер.

Как отвечать, чтобы вас запомнили

  1. Дайте короткое определение.
  2. Объясните механизм - как это работает внутри.
  3. Приведите пример из своего проекта.
  4. Назовите подводные камни и как вы их обходили.
Ответ «useMemo нужен для оптимизации» звучит одинаково у всех. Ответ с примером, где мемоизация не помогла и почему, запоминается.

Если вопрос незнакомый, не молчите: скажите, что знаете о смежной теме, и порассуждайте вслух. Интервьюеру важно, как вы думаете, - это ещё сильнее проявляется на лайвкодинге.

Такую структуру отрабатывают на мок-собеседованиях. Если хотите потренироваться с ментором, посмотрите трек Frontend на React и как проходит менторство.

Вопросы по теме

Какие хуки React спрашивают на собеседовании чаще всего?
Чаще всего - useState, useEffect и его массив зависимостей, useMemo и useCallback, useRef и useContext. Нередко просят написать собственный хук, например useDebounce или useFetch.
Спрашивают ли Next.js на собеседовании junior-разработчика?
Всё чаще: многие проекты используют Next.js. Достаточно понимать разницу между SSR, SSG, ISR и CSR, файловый роутинг и то, какие компоненты выполняются на сервере, а какие в браузере.
Зачем нужны ключи в списках React?
Ключ помогает React сопоставить элементы списка между рендерами и понять, какой элемент добавлен, удалён или перемещён. Индекс массива в качестве ключа ломает это сопоставление при вставке и сортировке, из-за чего теряется состояние элементов. Ключ должен быть стабильным и уникальным среди соседей.
Чем контролируемый компонент отличается от неконтролируемого?
В контролируемом компоненте значение поля хранится в состоянии React и меняется через обработчик. В неконтролируемом значение живёт в DOM, а React читает его через ref. Контролируемые удобнее для валидации на лету, неконтролируемые - проще и быстрее для больших форм, на этом подходе построен React Hook Form.
Как подготовиться к вопросам по React за короткий срок?
Пройтись по ключевым темам - рендеринг, хуки, состояние, производительность, Next.js - и для каждой подготовить ответ по схеме: определение, механизм, пример из своего проекта, подводные камни. Затем отрепетировать ответы вслух, лучше на мок-собеседовании.

Читайте также

Все статьи

Обсудим вашу подготовку?

Напишите, что уже умеете и с чем возникли трудности. Если есть проект, пришлите ссылку на него.

Отвечаю лично, поэтому прошу рассказать о ситуации подробно. Все поля обязательны, кроме отмеченных. После отправки покажу ссылку на мой Telegram: напишите туда, и начнём разговор.

Что не получается, что уже пробовали. От 100 знаков, сейчас 0.
Где работали или учились, сколько лет, какой стек, сколько откликов и собеседований. От 100 знаков, сейчас 0.
PDF или DOCX, до 5 МБ. Файл видит только администратор.
GitHub, hh, LinkedIn, сайт. Можно несколько, через пробел или с новой строки.