React: 18 сложных вопросов с объяснением, которые реально задают на собеседовании

18 сложных React-вопросов с объяснением: рендеринг, key, hooks, Context, forms, SSR, Suspense, React Query, performance и сильные ответы для middle-собеседования.

07 апреля 2026 г.25 минLexicon Team

Введение

Запрос на сложные React-вопросы обычно означает не список терминов, а попытку понять, где именно кандидат перестает опираться на шаблоны и начинает рассуждать как инженер. На сильном собеседовании уже недостаточно сказать, что useEffect запускается после рендера, Context нужен для избежания prop drilling, а useMemo помогает оптимизации. Интервьюер почти всегда идет дальше: просит объяснить, что реально происходит в дереве, где узкое место, чем это проверить и почему выбранный подход не сломает production через два месяца.

Эта статья сделана не вокруг одной подтемы, а вокруг набора сложных React-вопросов из уже покрытых кластеров: рендеринг, key, эффекты, формы, состояние, data fetching, SSR, Suspense, производительность и современная архитектура. Ниже будет короткий, но плотный разбор каждого вопроса. А там, где в блоге уже есть отдельный большой материал, я буду ссылаться именно на него: если по ходу чтения станет ясно, что темы не хватает, логичнее сразу переходить в профильную статью.

Больше вопросов в Telegram

Ежедневные разборы и реальные кейсы с интервью

Подписаться

Как читать эту подборку

Ниже вопросы идут не по API, а по инженерной сложности. Удобно держать в голове такую схему:

БлокЧто реально проверяютГде чаще всего теряют баллы
Renderingпонимаете ли вы, откуда берется обновлениесмешивают render и commit
Identityзнаете ли вы, как React сопоставляет элементыдумают, что key нужен только для warning
Hooksумеете ли вы работать с эффектами и зависимостямилечат симптомы и получают stale closure
Stateпонимаете ли вы границы ответственности stateглобализируют все подряд
Data fetchingумеете ли вы отличать server state от UI stateсмешивают fetch, cache и экранный черновик
Performanceумеете ли вы измерять, а не угадыватьначинают с useMemo, а не с диагностики
SSR/RSCпонимаете ли вы границы клиента и серверапутают SSR, hydration и Server Components

Архитектурный разбор: почему сложные React-вопросы всегда про модель, а не про API

Почти любую сложную React-задачу можно разложить на четыре шага:

  1. Где живет источник истины: в локальном state, в DOM, в query cache, в URL, на сервере или в глобальном store.
  2. Что именно запускает обновление: input, click, async completion, refetch, route change, hydration.
  3. Какой участок дерева затрагивается: один компонент, поддерево, provider, весь экран.
  4. Какова цена обновления: дешевый render, дорогой commit, большой DOM, длинный task в main thread, повторный сетевой запрос.

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

18 сложных вопросов с объяснением

1. Почему компонент перерендерился, хотя "данные не менялись"?

Потому что для React важно не только логическое равенство, но и источник обновления. Перерендер может произойти из-за локального state, новых props, обновления родителя, изменения context или смены key. Даже если "по смыслу" данные те же, новая ссылка на объект или функцию уже считается изменением.

Фраза вроде "React просто снова все перерисовал" звучит слишком общей. Намного лучше сначала определить триггер обновления и проверить, был ли это local state, parent rerender, context update или новая identity в props.

Если хотите пройти именно механику триггеров без сокращений, она подробно разобрана в отдельной статье про React rendering.

2. Почему render не равен обновлению DOM?

Потому что render — это вычислительная фаза. React пересчитывает дерево, а затем через согласование решает, что действительно изменилось. DOM затрагивается только на commit-фазе и только там, где есть реальные различия.

Это один из самых частых фильтров на middle-собеседованиях. Как только кандидат отождествляет render с фактической отрисовкой, почти все дальнейшие ответы про performance начинают расползаться.

3. Зачем React нужен key, если список и так работает?

Key нужен не для того, чтобы "убрать warning", а для сохранения identity элемента между рендерами. Когда элементы перемещаются, удаляются или вставляются, React должен понять, какой из них является прежним узлом, а какой новым. Без стабильного key начинают путаться локальное состояние, фокус, эффекты и порядок обновления.

Если хочется пройти не короткую версию, а реальные production-сценарии, где это ломается, они собраны в статье про ошибки с React keys.

4. Почему index как key иногда работает, а иногда ломает интерфейс?

Потому что в статичном списке без переупорядочивания он часто не проявляет проблему. Но как только порядок меняется, React начинает сопоставлять элементы по позиции, а не по сущности. Из-за этого состояние "переезжает" между строками, ломаются формы, сбивается фокус и появляются трудноуловимые баги.

Хороший ответ здесь не звучит как запрет ради запрета. Он объясняет, в каком классе интерфейсов index еще допустим, а в каком начинает создавать ложную identity.

5. Почему useEffect так часто становится источником багов?

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

Отдельно вся эта тема уже разложена в 15 сложных вопросах по useEffect и в статье о том, почему useEffect вызывает баги.

6. Что такое устаревшее замыкание (stale closure) простыми словами, но без потери точности?

Это ситуация, когда функция внутри эффекта, таймера или callback продолжает видеть старое значение переменной из того рендера, в котором она была создана. React здесь ни при чем сам по себе: это следствие модели замыканий в JavaScript и неправильной работы с зависимостями.

Хороший ответ всегда связывает устаревшее замыкание с двумя вещами: порядком рендера и dependency array. Иначе это звучит как магический баг, а не как объяснимая причина.

7. Когда useMemo действительно помогает, а когда это почти всегда лишнее?

Он полезен, когда есть дорогое вычисление или нужна стабильная ссылка на объект/массив для чувствительного дочернего компонента. Если вычисление дешево, а downstream-потребитель не выигрывает от стабильности ссылки, useMemo только усложняет код.

Если нужен более подробный практический разбор, он уже есть в статье про React.memo, useMemo и useCallback и в отдельном материале про то, как реально работает memoization.

8. Почему React.memo не всегда убирает лишние ререндеры?

Потому что он делает поверхностное сравнение пропсов, а не магически "замораживает" компонент. Новый объект, массив или callback в props уже ломает это сравнение. Кроме того, memo не защищает компонент от собственного state и от обновлений context.

Здесь обычно хорошо звучит ответ в духе: сначала посмотреть, что именно меняется в props, и не идет ли обновление через Context или parent subtree.

9. Когда Context удобен, но начинает ломать performance?

Когда один провайдер держит слишком широкий объект и обновляется часто. Тогда любой подписчик начинает участвовать в волне перерендеров, даже если ему нужна лишь малая часть значения.

Если хотите отдельно пройти выбор между Context, Redux и Zustand, это уже разобрано в сравнении Redux vs Zustand vs Context, а про уместность Context отдельно написано в статье React Context API: когда использовать.

10. Что чаще всего ломает большие React-формы?

Не сам input, а модель состояния. Проблемы начинаются, когда вся форма живет в одном объекте, каждая буква перерендеривает большой экран, асинхронная валидация не умеет отменяться, а серверные ошибки смешаны с локальными. Плюс часто теряется разделение между controlled и uncontrolled полями.

Если хотите отдельно пройти эту тему глубже, откройте статью про сложные вопросы по React-формам и разбор controlled vs uncontrolled компонентов.

11. Как отличить клиентское состояние (client state) от серверного состояния (server state) в хорошем ответе?

Client state — это состояние интерфейса: открыт ли выпадающий список, что набрано в поле ввода, какая вкладка активен. Server state — это данные, пришедшие снаружи, со своими правилами кэширования, refetch, invalidation и устаревания.

Если кандидат смешивает эти два слоя, почти всегда начинаются странные ререндеры, перетирание черновиков и ненужные refetch. Именно поэтому data fetching нельзя обсуждать только через useEffect.

12. Почему связка useEffect + fetch — уже не лучший универсальный ответ на вопрос о загрузке данных?

Потому что он не закрывает кэш, дедупликацию, инвалидацию, состояния гонки (race conditions) и фоновые обновления. Для production это слишком низкоуровневый слой. Он может быть уместен в простых сценариях, но уже не является дефолтным зрелым ответом для сложного приложения.

Если нужен более широкий обзор подходов, он уже есть в статье про React data fetching паттерны. А если хочется отдельно разобрать кэш и invalidation, посмотрите материал про React Query и сравнение SWR vs React Query.

13. Что важно объяснить про React Query на интервью, кроме "это библиотека для запросов"?

Нужно показать, что вы понимаете query cache, наблюдателей (observers), модель устаревших/свежих данных, invalidation и различие между server state и локальным UI state. Формулировка "удобно, потому что меньше кода" тут звучит слабо. Намного убедительнее объяснить, как библиотека снижает число ошибок вокруг cache lifecycle и фоновых обновлений.

14. Чем Suspense интересен на интервью, а не только в документации?

Тем, что показывает зрелость мышления о границах ответственности. Suspense — это не про красивый запасной интерфейс (fallback), а про модель ожидания данных или кода, структуру границ загрузки и поведение интерфейса при частичной готовности дерева.

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

15. Как кратко, но правильно объяснить разницу между SSR, CSR и RSC?

CSR — клиент сам строит интерфейс после загрузки JS. SSR — сервер заранее отдает HTML, а клиент потом гидратирует интерактивность. RSC — часть дерева рендерится на сервере как серверные компоненты без отправки лишнего клиентского кода в браузер.

Фраза "SSR быстрее, CSR хуже, RSC это новый SSR" звучит слишком грубо и обычно сразу выдает поверхностное понимание. Намного точнее говорить, что это разные архитектурные модели с разной ценой по интерактивности, bundle size, кэшу, DX и ограничениям по клиентскому состоянию.

Если хотите отдельно разобрать эту границу, посмотрите статью SSR vs CSR vs RSC и материал про Server Components.

16. Почему гидратация (hydration) — отдельная тема, а не просто "последний шаг SSR"?

Потому что именно на hydration часто уезжает пользовательский опыт: большой клиентский JS, дорогие commit, несоответствие разметки (mismatch), задержка интерактивности, разные значения на сервере и клиенте. На слабых устройствах это особенно заметно.

Если нужна именно механика процесса, она уже подробно разобрана в статье про hydration в React, а production-ошибки отдельно вынесены в материал про hydration errors.

17. Как правильно отвечать на вопрос про performance, чтобы не звучать как человек, который знает только useMemo?

Через диагностику. Нужно отделить стоимость рендера, стоимость фиксации, работу браузера, гидратацию и задержку сети. Только после этого выбирать инструмент: локализация state, разбиение provider, мемоизация, виртуализация, разделение кода (code splitting), server-first решение.

Если хотите пройти именно механику такого ответа, она подробно собрана в статье про React performance profiling и в материале про оптимизацию React для middle.

18. Как выглядит сильный ответ на вопрос "что бы вы оптимизировали первым?"

Не "добавил бы memo", а такая цепочка:

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

Именно такой ответ чаще всего отличает уверенного middle от кандидата, который просто много читал.

Прокачай React за 7 дней

20 вопросов и разборов по React Hooks

Начать

Код-пример 1: слабый и сильный ответ про загрузку данных

Слабый вариант:

import { useEffect, useState } from "react";

export function Users({ query }: { query: string }) {
  const [users, setUsers] = useState<any[]>([]);

  useEffect(() => {
    fetch(`/api/users?q=${query}`)
      .then((r) => r.json())
      .then(setUsers);
  }, [query]);

  return <UserList items={users} />;
}

Такой код может работать локально, но он оставляет без ответа важные вопросы: что с отменой запроса, как устроен жизненный цикл кэша, где обработка ошибки, как избежать устаревшего ответа.

Более зрелая версия хотя бы убирает гонку:

import { useEffect, useState } from "react";

type User = { id: string; name: string };

export function Users({ query }: { query: string }) {
  const [users, setUsers] = useState<User[]>([]);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    const controller = new AbortController();
    setError(null);

    fetch(`/api/users?q=${encodeURIComponent(query)}`, {
      signal: controller.signal,
    })
      .then((r) => {
        if (!r.ok) throw new Error("Request failed");
        return r.json();
      })
      .then((data: User[]) => setUsers(data))
      .catch((e: Error) => {
        if (e.name !== "AbortError") {
          setError("Не удалось загрузить пользователей");
        }
      });

    return () => controller.abort();
  }, [query]);

  if (error) return <p>{error}</p>;
  return <UserList items={users} />;
}

Но и это не "финальный правильный ответ" для любой системы. На сложном экране чаще стоит обсуждать data layer и query cache, а не вручную писать этот шаблон в каждом компоненте.

Код-пример 2: почему memo не сработал

import React, { useState } from "react";

const Row = React.memo(function Row({
  item,
  onOpen,
}: {
  item: { id: string; title: string };
  onOpen: (id: string) => void;
}) {
  return <button onClick={() => onOpen(item.id)}>{item.title}</button>;
});

export function Table({ items }: { items: { id: string; title: string }[] }) {
  const [selectedId, setSelectedId] = useState<string | null>(null);

  return (
    <>
      {items.map((item) => (
        <Row
          key={item.id}
          item={item}
          onOpen={(id) => setSelectedId(id)}
        />
      ))}
      <p>Выбрано: {selectedId ?? "ничего"}</p>
    </>
  );
}

Row мемоизирован, но onOpen создается заново на каждом рендере. Значит, поверхностное сравнение видит новый prop и memo не экономит работу. Именно в таких местах важно не просто знать useCallback, а понимать, зачем он нужен и когда его цена оправдана.

Риски и сложности в продакшене

1. Кандидат лечит симптомы, а не архитектуру

Вместо ответа про границы state и data flow начинается перечисление useMemo, useCallback, React.memo. Это слабый сигнал: человек видит инструменты, но не модель проблемы.

2. Смешиваются server state, UI state и черновики

В production это ведет к перезаписи пользовательского ввода, лишним refetch и каскадам обновлений. На интервью это слышно в ответах, где query-данные предлагают держать и редактировать как обычный локальный state без оговорок.

3. Любая server-first тема сводится к лозунгам

Кандидат говорит, что "Next.js быстрее" или "RSC уменьшает бандл", но не может объяснить, что именно происходит с hydration, клиентским JS и интерактивностью.

4. Производительность обсуждается без метрики

Ответы про optimization без Profiler, без пользовательского сценария и без компромисса по сложности кода почти всегда звучат декоративно.

Разбор производительности

У сложных React-вопросов про performance почти всегда повторяется один и тот же набор аспектов:

  • latency: насколько быстро интерфейс отвечает на ввод, переход, submit
  • throughput: сколько работы делает система при серии обновлений
  • memory: сколько кэша и удерживаемых структур создается ради оптимизации
  • complexity: насколько труднее команде понимать и поддерживать код

Например, useMemo может снизить CPU-стоимость, но увеличивает сложность и риск ложных зависимостей. React Query упрощает cache lifecycle, но добавляет концептуальный слой. RSC уменьшает клиентский JS, но меняет архитектуру границ между сервером и клиентом.

Хороший ответ честно признает этот компромисс (trade-off). Формулировка "это уместный способ при таких ограничениях" почти всегда звучит взрослее, чем попытка назвать один универсально лучший вариант.

Практики, которые реально помогают

  • Разделяйте local UI state, server state и derived state.
  • Не используйте useEffect для того, что можно вычислить на render или обработать в event handler.
  • Стабилизируйте key по сущности, а не по позиции.
  • Делите большие provider-зоны, если они обновляются с разной частотой.
  • Не добавляйте мемоизацию без измеримой проблемы.
  • Для data fetching сначала думайте про lifecycle данных, а потом про конкретный hook.
  • Для SSR и RSC всегда проговаривайте цену hydration и размер клиентского кода.

Частые ошибки

  • Путать рендер и фиксацию (commit).
  • Использовать index как key в динамическом списке.
  • Говорить "useEffect нужен для запросов" как универсальную формулу.
  • Лечить любой ререндер useMemo.
  • Считать Context универсальным глобальным store.
  • Говорить про Suspense только как про loading fallback.
  • Сводить SSR/RSC к маркетинговым тезисам без архитектурного объяснения.

Как отвечать на интервью

Рабочая формула ответа обычно выглядит так:

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

Если вопрос звучит: "Почему этот экран тормозит?", хороший ответ не начинается с useMemo. Он начинается со слов: "Сначала я разделю проблему на рендер, фиксация, работа браузера и сеть, а потом проверю ее через Profiler и Browser Performance". Именно такое мышление и считывается как middle+.

Подготовьтесь к сложным React-вопросам в формате реального интервью

Практика по hooks, rendering, state management, performance, SSR и современному React с разбором сильных и слабых ответов, а не по шаблонным шпаргалкам

Начать подготовку

FAQ

Какие темы углубить после этой статьи в первую очередь?

Если плавает база, начните с рендеринга, reconciliation и key. Если провисают side effects, идите в useEffect. Если основной страх — production-вопросы, переходите к performance profiling, state management и SSR/RSC.

Чем эта статья отличается от подборки задач по React?

Здесь фокус именно на устных сложных вопросах и логике сильного ответа. Для задач и практических сценариев в коде лучше отдельно открыть 20 задач по React с разбором.

Нужно ли открывать все статьи по ссылкам подряд?

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

Какая одна ошибка чаще всего валит сильных по коду кандидатов?

Они отвечают на React-вопросы как на набор API, а не как на модель обновления интерфейса. Это особенно заметно на темах performance, data fetching и SSR.

Что лучше тренировать после чтения: код или устные ответы?

Оба формата, но в связке. Сначала коротко проговорите ответ на вопрос, потом напишите минимальный пример и объясните его ограничения. Так лучше всего закрепляется причинно-следственная модель.

Итоги

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

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

Больше вопросов в Telegram

Ежедневные разборы и реальные кейсы с интервью

Подписаться

Автор

Lexicon Team

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