> Как React отслеживает количество вызовов хуков между рендерами? (React)

Уровень: senior · Роль: frontend · Категория: Технические вопросы

Компании: Black Wall Group (BWG)

Стек: React

> Пример ответа

Короткий ответ

React отслеживает количество вызовов хуков между рендерами с помощью связанного списка (linked list) узлов хуков, хранящегося в fiber-узле компонента. Каждый хук имеет индекс, который увеличивается при каждом вызове хука во время рендера. React сравнивает количество вызовов хуков с предыдущим рендером и выбрасывает ошибку при несоответствии.

Подробное объяснение

React использует внутреннюю структуру данных, называемую fiber, для каждого компонента. Внутри fiber есть свойство memoizedState, которое указывает на первый узел связанного списка хуков. Каждый узел содержит:

  • queue - очередь обновлений для хука
  • next - указатель на следующий хук в списке
  • memoizedState - текущее значение состояния

Во время рендера React проходит по этому списку, используя глобальный счетчик currentlyRenderingFiber.memoizedState. При каждом вызове хука (useState, useEffect и т.д.) React:

  1. Берет текущий узел из списка по индексу
  2. Выполняет логику хука
  3. Перемещает указатель на следующий узел

Если количество вызовов хуков не совпадает с количеством узлов в списке, React обнаруживает несоответствие и выбрасывает ошибку "Rendered fewer hooks than expected" или "Rendered more hooks than expected".

На практике

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

Пример кода

JAVASCRIPT
// Правильно - одинаковое количество хуков на каждом рендере
function MyComponent() {
const [count, setCount] = useState(0);
const [name, setName] = useState('John');
useEffect(() => {
document.title = `Count: ${count}`;
}, [count]);
return <div>{name}: {count}</div>;
}
// Неправильно - условный вызов хука
function BadComponent({ condition }) {
const [count, setCount] = useState(0);
if (condition) {
const [name, setName] = useState('John'); // Ошибка!
}
return <div>{count}</div>;
}

Как отвечать на собеседовании

Начни с объяснения fiber-архитектуры и связанного списка хуков. Упомяни, что React хранит хуки в порядке их вызова и использует индекс для сопоставления. Подчеркни, что это причина правила "не вызывать хуки в циклах, условиях и вложенных функциях". Добавь, что React использует двойное буферизирование (work-in-progress tree) для сравнения хуков между рендерами.

Что проверяет интервьюер

  • Понимание внутреннего устройства React (fiber, linked list)
  • Знание правил хуков и их обоснования
  • Способность объяснить, почему хуки должны вызываться в одном порядке
  • Понимание механизма обнаружения ошибок в React

Типичные ошибки

  • Утверждение, что React использует массив для хранения хуков (на самом деле - связанный список)
  • Непонимание, почему ранний return ломает порядок хуков
  • Путаница между fiber и virtual DOM
  • Отсутствие упоминания двойного буферизирования при сравнении рендеров

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью