ГлавнаяБлогReact Native: подготовка к собеседованию с нуля до сеньора
Собеседования

React Native: подготовка к собеседованию с нуля до сеньора

Гайд по React Native для собеседований: разбор реальных сценариев, примеры кода и глубокие объяснения. Начни готовиться сейчас!

Al
Редакция Algolitalgolit.ru
15 мин чтения19 июня 2026 г.

Почему этот гайд отличается от других

Большинство блогов по подготовке кидают в вас определениями: «Компонент — это переиспользуемая часть UI». С таким ответом вас не возьмут. Настоящие собеседования — не тест на словарный запас. Интервьюер описывает ситуацию — приложение тормозит, список слишком часто перерисовывается, экран зависает — и смотрит, как вы мыслите. Он хочет понять, почему что-то работает, а не как это называется.

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

Читайте медленно, проговаривайте ответы вслух. К концу вы не просто запомните ответы — вы поймёте React Native.

React Native и основы JS. Жизненный цикл приложения

Q1. Пользователь заполнял длинную форму, переключился в другое приложение, вернулся — данные пропали. Что произошло и как исправить?

Когда пользователь покидает приложение, ОС может перевести его в фоновый режим, а при нехватке памяти — полностью завершить процесс. Если данные формы хранились только в состоянии компонента (useState в памяти), они исчезают вместе с процессом.

Исправление зависит от данных:

  • Для временного состояния UI — слушайте AppState и сохраняйте черновик при уходе в фон.
  • Для любых данных, которые пользователь не хочет терять, сохраняйте их по мере ввода в локальное хранилище (AsyncStorage/MMKV для небольших значений, SQLite для реальных данных), а не только при выходе.
  • Восстановите черновик при монтировании экрана.

Сеньорный уровень: Различайте ре-рендер (дешёвый, частый — состояние сохраняется), размонтирование (компонент покинул дерево — его состояние пропадает, если не поднято или не сохранено) и завершение процесса (ОС убила приложение — выживают только сохранённые данные). Большинство багов с потерей данных возникают из-за путаницы между этими понятиями. Тестируйте завершение процесса, убивая приложение из фона.

Q2. Пройдёмся по жизненному циклу приложения React Native (AppState). В каком состоянии находится приложение при входящем звонке?

React Native предоставляет состояние приложения через AppState с тремя значениями:

  • active — приложение работает на переднем плане и получает ввод.
  • inactive — переходное состояние (iOS): приложение на переднем плане, но не получает события, например, при наложении экрана звонка или в переключателе приложений.
  • background — приложение не видимо, работает в фоне. Хорошее место для сохранения состояния и остановки работы.

(На Android inactive фактически не используется так же; в основном вы видите active и background.)

При входящем звонке: приложение переходит в inactive (UI звонка прерывает его на iOS); если пользователь уходит из приложения для ответа на звонок, оно переходит в background.

Ключевое правило: сохраняйте состояние и приостанавливайте работу (таймеры, видео, геолокацию) при background/inactive; возобновляйте при active. Подписывайтесь через AppState.addEventListener('change', handler) и отписывайтесь при размонтировании.

Q3. В чём разница между props и state? Приведите реальный пример использования каждого.

props — данные, передаваемые в компонент от родителя. Они доступны только для чтения внутри дочернего компонента — он отображает или использует их, но не изменяет. Используйте props для настройки компонента: Button получает title и onPress.

state — данные, принадлежащие и управляемые компонентом, которые могут меняться со временем, вызывая ре-рендер. Используйте state для вещей, изменяющихся в результате взаимодействия или данных: вкл/выкл тумблера, ввод формы, статус загрузки.

Реальный пример: PriceTag, который просто показывает переданную цену — только props. LikeButton, который переключается между заполненным и пустым при нажатии — state для флага лайка.

Нюанс для сеньора: «Данные текут вниз» — родители передают props детям; дети сообщают наверх через колбэки. Поднятие состояния на правильный уровень (и его недублирование) — ключевой навык. Чрезмерное использование локального state для общих данных ведёт к prop-drilling и багам.

Q4. Что такое useEffect и где бы вы настроили и отключили подписку?

useEffect выполняет побочные эффекты в функциональных компонентах — вещи вне чистого рендеринга: подписки, таймеры, сетевые вызовы, обработчики событий. Он запускается после рендера, а массив зависимостей контролирует, когда он перезапускается.

  • useEffect(fn, []) — запускается один раз после первого рендера (монтирование). Здесь настраивайте подписку.
  • useEffect(fn, [dep]) — перезапускается при изменении dep.

Очистка: верните функцию из эффекта — React вызывает её при размонтировании и перед повторным запуском эффекта. Отписывайтесь/очищайте таймеры здесь.

useEffect(() => {
  const sub = AppState.addEventListener('change', onChange);
  return () => sub.remove(); // очистка при размонтировании
}, []);

Правило, которое любят интервьюеры: что настроили в эффекте — то и отключайте в очистке. Забытая очистка приводит к утечкам подписок/таймеров и багам «обновление состояния на размонтированном компоненте».

Q5. Объясните массив зависимостей useEffect и самую частую ошибку, которую допускают разработчики.

Массив зависимостей указывает React, когда перезапускать эффект — он перезапускается при изменении любого перечисленного значения. Три случая: [] (один раз), [a, b] (при изменении a или b) и отсутствие массива (после каждого рендера).

Самая частая ошибка — stale closures / пропущенные зависимости: если эффект использует значение (проп, состояние или функцию), но вы не указали его в зависимостях, эффект захватывает старое (устаревшее) значение и никогда не обновляется — например, setInterval, который всегда логирует начальное значение. И наоборот, указание нестабильного значения (функции/объекта, создаваемого заново при каждом рендере) в зависимостях приводит к постоянному перезапуску эффекта (бесконечный цикл переподписок).

Исправления: включайте все используемые значения и стабилизируйте функции/объекты с помощью useCallback/useMemo, чтобы они не меняли идентичность при каждом рендере. Правило ESLint react-hooks/exhaustive-deps ловит пропущенные зависимости. Объяснение stale closures — сильный сеньорный сигнал.

Q6. Что такое виртуальный DOM и согласование (reconciliation) и как это применяется в React Native?

React хранит лёгкое in-memory дерево, описывающее ваш UI (виртуальное дерево). При изменении состояния/пропов React строит новое дерево и сравнивает его со старым (согласование), чтобы вычислить минимальный набор изменений, а затем применяет только их.

В React Native нет браузерного DOM — вместо этого React согласует дерево компонентов и отправляет минимальные обновления на нативную сторону, которая обновляет реальные нативные вью (UIView/ViewGroup). Та же идея сравнения, но вывод — нативные вью, а не HTML.

Почему это важно: поэтому важны ключи в списках (они помогают сравнению правильно сопоставлять элементы) и почему лишние ре-рендеры — это лишняя работа: React всё равно должен их согласовать. Понимание согласования лежит в основе большинства ответов по производительности.

Q7. В чём разница между контролируемым и неконтролируемым компонентом (например, TextInput)?

Контролируемый — значение компонента управляется состоянием. TextInput получает значение из state, а onChangeText обновляет этот state. React — единый источник истины:

<TextInput value={text} onChangeText={setText} />

Неконтролируемый — компонент управляет своим внутренним значением; вы читаете его только когда нужно (например, через ref). React не управляет каждым нажатием клавиши.

Компромисс: контролируемые входы дают полный контроль (валидация, форматирование, синхронизация), но вызывают ре-рендер при каждом нажатии; неконтролируемые легче, но их сложнее контролировать. Сценарий: форма с живой валидацией → контролируемый. Простой ввод, где нужно только финальное значение → неконтролируемый (ref) может избежать ре-рендеров на каждое нажатие. Знание этого компромисса показывает реальный опыт работы с формами.

Q8. Приложение показывает пустой/сплеш-экран слишком долго до появления UI. Почему и как это исправить?

Задержка — это время запуска: нативное приложение запускается, движок JS (Hermes) загружает и парсит ваш JS-бандл, и React рендерит первый экран. Выполнение тяжёлой синхронной работы при запуске увеличивает задержку.

Причины и исправления:

  • Большой JS-бандл → включите Hermes (предварительная компиляция JS в байт-код для быстрого запуска), включите RAM bundle/inline requires и лениво загружайте тяжёлые экраны/модули.
  • Тяжёлая синхронная работа в первом рендере компонента или в коде модуля верхнего уровня → отложите её (запустите после первой отрисовки, используйте InteractionManager).
  • Слишком много библиотек, инициализируемых сразу → ленивая инициализация.
  • Используйте правильный нативный сплеш-экран (react-native-bootsplash), чтобы ожидание выглядело намеренным.

Сеньорный момент: «Измеряйте с помощью Flipper / профайлера перед оптимизацией» и упомяните Hermes + inline requires как самые большие выигрыши в скорости запуска. Это показывает актуальные практические знания.

Q9. Как правильно передавать данные между двумя экранами в React Native?

Зависит от направления и области видимости:

  • Вперёд (A → B): передавайте данные через параметры навигации: navigation.navigate('Detail', { id: productId }), читайте через route.params. Передавайте идентификаторы или небольшие данные, не огромные объекты.
  • Назад (B → A): используйте колбэк, переданный в параметрах, или лучше обновите общее состояние (Context/Redux/Zustand) или инициируйте повторную загрузку (React Query), которую A наблюдает.
  • Общие/глобальные данные: используйте глобальное управление состоянием, чтобы несколько экранов читали из одного источника истины вместо передачи данных через навигацию.

Почему не глобальная переменная / мутируемый модуль: это создаёт скрытую связанность, сложно тестируется и не вызывает ре-рендеры. Параметры навигации (явные) или ограниченное состояние (общее) — чистые варианты.

Q10. Что на самом деле происходит, когда вы вызываете setState/сеттер состояния из useState?

Вызов сеттера состояния (например, setCount(1)) делает две вещи: он планирует обновление с новым значением и помечает компонент для ре-рендера. При следующем рендере useState возвращает новое значение, и React согласует новый вывод со старым для обновления нативных вью.

Ключевые детали, которые проверяют интервьюеры:

  • Обновления состояния асинхронны/батчатся — вызов setCount(count + 1) дважды подряд может не прибавить 2, потому что оба читают одно и то же count. Используйте функциональный обновлятор setCount(c => c + 1) для обновления на основе последнего значения.
  • Сеттер заменяет значение (не сливает, как старый классовый setState) — для объектов распространяйте старое состояние самостоятельно.

Знание батчинга и функционального обновлятора — очень частый практический вопрос.

Q11. Почему useState перестаёт быть достаточным по мере роста приложения? Обоснуйте необходимость управления состоянием.

useState идеален для локального, эфемерного состояния внутри одного компонента. Но по мере роста приложения вы сталкиваетесь с ограничениями:

  • Совместное использование состояния между удалёнными компонентами заставляет поднимать состояние и передавать его через много слоёв (prop drilling) — утомительно и хрупко.
  • Серверные данные (кэшированные ответы API, повторная загрузка, кэширование, инвалидация) неудобно управлять вручную с помощью useState/useEffect.
  • Сложное/связанное состояние, разбросанное по компонентам, становится трудно понять и тестировать.

Поэтому нужны способы совместного использования состояния (Context, Redux, Zustand) и специализированные инструменты для серверного состояния (React Query). Формулировка проблемы перед называнием решений — сеньорный подход, и она задаёт различие между клиентским и серверным состоянием, что является главной темой 2026 года.

Q12. ОС убила ваше приложение в фоне, и пользователь потерял своё место. Как корректно восстановить его?

ОС освобождает память, незаметно убивая фоновые приложения. Чтобы вернуть пользователя, объедините уровни:

  • Сохраняйте критические данные (черновики, выделения, незавершённую работу) в локальное хранилище при каждом значимом изменении.
  • Восстанавливайте состояние при монтировании экрана, проверяя сохранённые данные.
  • Используйте AppState для сохранения при уходе в фон.

Сеньорный момент: «Не полагайтесь только на componentWillUnmount — процесс может быть убит без его вызова. Сохраняйте проактивно, а не только при выходе».

#react native#собеседование#подготовка#разработка#мобильные приложения
Al
Редакция Algolit

Пишем про алгоритмы, подготовку к собеседованиям и карьеру в IT — так, чтобы было понятно и полезно.

Хочешь закрепить знания на практике?

Решай задачи на Algolit — интерактивная платформа для обучения

Начать бесплатно →