Как работает Fiber-архитектура в React?
Суть проблемы, которую решает Fiber
До React 16 согласование (reconciliation) выполнялось по алгоритму Stack Reconciler: обход дерева компонентов был рекурсивным и синхронным, без возможности прерваться. При большом дереве это блокировало поток JS на всё время обновления, вызывая просадки FPS и залипание UI при вводе.
Fiber — это переписанный реконсилер, превращающий рекурсивный обход в дерево связанных объектов (fiber-узлов) и итеративный цикл работы, который можно приостанавливать, возобновлять, распределять по приоритетам и даже отбрасывать.
Структура fiber-узла
Каждый компонент/элемент представлен fiber-объектом с полями:
type,key— что рендеримchild,sibling,return— связи как в связном списке/дереве, заменяющие рекурсию обходом по ссылкамpendingProps/memoizedProps— новые и уже отрисованные пропсыalternate— ссылка на fiber из другого дерева (double buffering)flags— side-effect теги: Placement, Update, Deletion и т.д.lanes— приоритет обновления
Double buffering: current и work-in-progress
React держит два дерева файберов: current (то, что уже отрисовано на экране) и workInProgress (строящееся обновление). Они связаны через alternate. Когда работа над WIP-деревом завершена и закоммичена, WIP становится новым current, а старое дерево переиспользуется под следующее обновление — это экономит аллокации.
Две фазы: render и commit
- Render/Reconciliation — обход дерева функциями
beginWork/completeWork: вычисление нового состояния, сравнение с предыдущим деревом, простановка flags. Фаза прерываемая: React может остановиться после обработки очередного fiber-узла, отдать управление браузеру (например, для обработки инпута), а потом продолжить с того же места. - Commit — применение накопленных side-effects к реальному DOM. Эта фаза всегда синхронная и непрерываемая, чтобы пользователь не увидел промежуточное состояние интерфейса.
Кооперативный планировщик и приоритеты
Прерываемость реализована через scheduler: работа режется на units of work — по одному fiber-узлу за раз. После каждого узла React проверяет через shouldYield, остался ли лимит времени в текущем кадре (около 5 мс). Если лимит исчерпан, управление отдаётся браузеру. Обновления имеют разные приоритеты (lanes): пользовательский ввод обрабатывается синхронно, а transitions и фоновая работа — с более низким приоритетом и могут быть прерваны более срочным обновлением.
Что это даёт
Fiber — фундамент конкурентных возможностей React: startTransition, useDeferredValue, Suspense, стриминговый SSR. Без возможности прерывать и приоритизировать рендер эти механизмы были бы невозможны.
Что хочет услышать интервьюер
Понимание, что Fiber — это структура данных плюс алгоритм обхода, а не просто «новый рендерер»
Знание, что render-фаза прерываема, а commit-фаза всегда синхронна
Понимание double buffering — пары current/workInProgress через alternate
Знание про lanes/приоритеты и их связь с concurrent-фичами (transitions, Suspense)
Умение отличить beginWork/completeWork (render) от применения side-effects (commit)
Пример: Упрощённая структура fiber-узла
type Fiber = {
type: any; // компонент или тег DOM-элемента
key: string | null;
// связи дерева вместо рекурсии
child: Fiber | null;
sibling: Fiber | null;
return: Fiber | null; // родитель
pendingProps: any; // новые пропсы для этого рендера
memoizedProps: any; // пропсы, уже отрисованные ранее
memoizedState: any; // состояние хуков/класса
alternate: Fiber | null; // связь с fiber-ом из другого дерева
flags: number; // side-effect теги: Placement, Update, Deletion
lanes: number; // приоритет обновления
};
Пример: Упрощённый кооперативный цикл работы
let workInProgress: Fiber | null = null;
function workLoopConcurrent() {
// обрабатываем по одному fiber-узлу, пока есть время в кадре
while (workInProgress !== null && !shouldYield()) {
workInProgress = performUnitOfWork(workInProgress);
}
}
function performUnitOfWork(unitOfWork: Fiber): Fiber | null {
// спускаемся вглубь дерева, создавая дочерние fiber-узлы
const next = beginWork(unitOfWork);
if (next === null) {
// дошли до листа — поднимаемся обратно и завершаем узлы
completeUnitOfWork(unitOfWork);
}
return next;
}
// если время кадра вышло — React отдаёт управление браузеру
// и продолжит с сохранённого workInProgress на следующем тике
Типичные ошибки
Путают Fiber с виртуальным DOM в целом, будто это одна и та же концепция
Считают, что весь рендеринг React теперь асинхронный, включая запись в реальный DOM
Не могут объяснить, зачем нужны два дерева (current и work-in-progress)
Не знают про lanes и приоритеты, думают, что прерывание работает только по таймеру
Описывают устаревший effect list из ранних версий React 16 вместо актуального обхода по flags


