PassFront
  1. PassFront
  2. База знаний
  3. Рендеринг и производительность

Как изменение states в одном месте в React влияло на рендеринг?

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

Место хранения состояния определяет объём перерисовок. Работает правило каскада: обновление state рендерит компонент-владелец и всё его поддерево.

Эффект «состояние наверху»

const App = () => {
  const [query, setQuery] = useState(''); // состояние в корне
  return (
    <>
      <Search value={query} onChange={setQuery} />
      <Sidebar />       {/* перерисовывается на каждый символ */}
      <HeavyReport />   {/* и этот тоже */}
    </>
  );
};

Одно изменение в корне → рендер всей страницы. Симптом: ввод в поле подтормаживает, профайлер показывает вспышку по всему дереву.

Как это лечится

Спуск состояния вниз: перенести useState внутрь Search — соседи перестают рендериться вовсе. Самый дешёвый и надёжный приём.

children как проп: обёртка со state не перерисовывает переданных ей детей (их элементы созданы выше и стабильны).

React.memo на тяжёлых соседях + стабильные props (useCallback/useMemo) — прерывает каскад, но требует дисциплины.

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

Главное

Рендер ≠ обновление DOM: после диффа React может ничего не менять. Проблема возникает, когда рендеры частые (каждый символ) и дорогие (большие поддеревья, тяжёлые вычисления). Диагностика — React DevTools Profiler с опцией «why did this render».

Коротко для собеседования

Изменение state рендерит владельца и всё его поддерево, поэтому состояние, поднятое слишком высоко, перерисовывает всю страницу на каждый ввод. Лечится спуском состояния к месту использования, children-как-пропом, точечным React.memo и разделением контекстов/селекторами. Проверяется профайлером.

Другие вопросы раздела