Как React понимает что нужно что-либо перерендерить?
Рендеринг и производительность
React не «следит» за данными магически — он узнаёт о необходимости перерендера через явные вызовы своих API: сеттеры state, dispatch, изменение контекста, подписки на сторы.
Триггеры, о которых React знает
setState/ сеттерuseState/dispatchуuseReducer— прямой сигнал «состояние изменилось, запланируй рендер».- Изменение
valueу Context.Provider — пометить всех потребителей. useSyncExternalStore— внешний стор дёргает колбэк подписки.- Рендер родителя — дети рендерятся рекурсивно без всяких сигналов.
Именно поэтому мутация объекта state без вызова сеттера ничего не перерисует: React о ней просто не узнал.
Как решается, что рендерить
После сигнала React помечает компонент «грязным» и планирует работу (в React 18 — через собственный планировщик, с приоритетами и батчингом):
- сеттер сравнивает новое значение со старым (
Object.is) — то же значение → рендер пропускается; - рендерится помеченный компонент и его поддерево;
- новое виртуальное дерево сравнивается со старым (reconciliation);
- в реальный DOM вносятся только фактические отличия.
Пример
const [items, setItems] = useState([]);
items.push(newItem); // React НЕ узнает — мутация
setItems([...items, item]); // React узнает — вызван сеттер с новой ссылкойСравнение при диффе
На этапе сравнения деревьев React сопоставляет узлы по типу и key, а props — поверхностно. Новая ссылка при том же содержимом = «изменилось» (лишняя работа), та же ссылка = «не изменилось» (поддерево можно пропустить с React.memo).
Коротко для собеседования
React узнаёт об изменениях только через свои API: сеттеры useState/dispatch, изменение value контекста, подписки useSyncExternalStore. Затем помечает компонент, рендерит поддерево, диффом сравнивает виртуальные деревья и обновляет в DOM только отличия. Мутации без сеттера React не видит — отсюда требование иммутабельности.