Главная / Статьи / Скорость реакции начинается с организации дерева компонентов.

Скорость реакции начинается с организации дерева компонентов.

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

1699 слов

React выполняет то, что требует структура дерева. Когда приложение кажется медленным, это часто связано с тем, что фреймворк следует длинному пути распространения состояния/обновлений, а не с какими-то таинственными сбоями.

Повторная отрисовка — не враг

Отрисовки обеспечивают единообразие интерфейса. Настоящим врагом является ненужная работа с большими поддеревьями при каждом нажатии клавиши.

// ❌ count lives in Parent — expensive siblings re-render on every click
function Parent() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <button onClick={() => setCount(c => c + 1)}>Count: {count}</button>
      <ExpensiveComponent />
      <AnotherExpensiveComponent />
    </div>
  );
}
// ✅ count lives in Counter — expensive siblings are untouched
function Counter() {
  const [count, setCount] = useState(0);
  return (
    <button onClick={() => setCount(c => c + 1)}>
      Count: {count}
    </button>
  );
}

function Parent() {
  return (
    <div>
      <Counter />
      <ExpensiveComponent />
      <AnotherExpensiveComponent />
    </div>
  );
}
// ❌ SearchLayout owns state — ExpensiveList re-renders on every keystroke
function SearchLayout() {
  const [query, setQuery] = useState('');

  return (
    <div>
      <input value={query} onChange={e => setQuery(e.target.value)} />
      <ExpensiveList />
    </div>
  );
}
/* ✅ StatefulInput receives expensive content as children
 — its reference stays stable */
function StatefulInput({ children }) {
  const [query, setQuery] = useState('');
  return (
    <div>
      <input value={query} onChange={e => setQuery(e.target.value)} />
      {children}
    </div>
  );
}

function SearchLayout() {
  return (
    <StatefulInput>
      <ExpensiveList />
    </StatefulInput>
  );
}

Где должно прекратиться распространение

Размещение источника

Храните состояние рядом с компонентами, которые его записывают и читают. Текст черновика формы не обязательно должен находиться в корне приложения.

Блокировка пути

Дочерние компоненты, принимающие стабильные параметры, могут избежать участия в процессе. Использование композиции и подхода с дочерними компонентами в качестве слотов часто эффективнее, чем общий механизм сохранения состояния.

Дерево как дизайнерское решение

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

Начнем с дерева

Прежде чем приступать к микрооптимизациям, определите, какое состояние должно находиться где и какие поддеревья должны оставаться неизменными во время частых обновлений. Большинство проблем типа «React работает медленно» связаны именно с структурой дерева.

Сначала проанализируйте структуру, затем реорганизуйте код; кэширование добавляйте в конце.

Провайдеры контекста являются частью дерева: мегаконтекст, который меняется при каждой отрисовке, аннулирует эффект кэширования листовых элементов. Разделяйте контексты в зависимости от частоты обновлений.

Разделение кода на уровне маршрутов сокращает размер дерева, который необходимо обрабатывать при первой отрисовке; сочетайте это с локальным состоянием, чтобы сохранить легкость навигации.

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

Владение документом: какая команда владеет состоянием той или иной поддеревья. Общие глобальные хранилища вновь создают проблему широкого распространения изменений, только под другим названием.

Используйте функцию отслеживания времени выполнения операций в React Profiler до и после изменения состояния; сохраняйте отчет о различиях в PR для проверки.

Серверные компоненты и клиентские острова меняют местоположение дерева, но правила распространения изменений по-прежнему применяются на клиентском острове.

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

Разделение кода на уровне маршрутов сокращает размер дерева, за который вы платите при первой отрисовке; сочетайте это с локальным состоянием, чтобы сохранить легкость навигации.

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

Владение документом: какая команда владеет состоянием той или иной поддеревья. Общие глобальные хранилища вновь создают проблему широкого распространения изменений, только под другим названием.

Используйте функцию отслеживания времени выполнения операций в React Profiler до и после изменения состояния; сохраняйте отчет о различиях в PR для проверки.

Серверные компоненты и клиентские острова меняют местоположение дерева, но правила распространения изменений по-прежнему применяются на клиентском острове.

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

Разделение кода на уровне маршрутов сокращает размер дерева, за который приходится платить при первой отрисовке; сочетайте это с локальным состоянием, чтобы сохранить легкость навигации.

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

Владение документом: какая команда владеет состоянием той или иной поддеревья. Общие глобальные хранилища вновь создают проблему широкого распространения изменений, только под другим названием.

Используйте функцию отслеживания времени выполнения операций в React Profiler до и после изменения состояния; сохраняйте отчет о различиях в PR для проверки.

Серверные компоненты и клиентские острова меняют местоположение дерева, но правила распространения изменений по-прежнему применяются на клиентском острове.

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

Разделение кода на уровне маршрутов сокращает размер дерева, за который вы платите при первой отрисовке; сочетайте это с локальным состоянием, чтобы сохранить легкость навигации.

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

Владение документом: какая команда владеет состоянием той или иной поддеревья. Общие глобальные хранилища вновь создают проблему широкого распространения изменений, только под другим названием.

Используйте функцию отслеживания времени выполнения операций в React Profiler до и после изменения состояния; сохраняйте отчет о различиях в PR для проверки.

Серверные компоненты и клиентские острова меняют местоположение дерева, но правила распространения изменений по-прежнему применяются на клиентском острове.

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

Разделение кода на уровне маршрутов сокращает размер дерева, за который вы платите при первой отрисовке; сочетайте это с локальным состоянием, чтобы сохранить легкость навигации.

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

Владение документом: какая команда владеет состоянием той или иной поддеревья. Общие глобальные хранилища вновь создают проблему широкого распространения изменений, только под другим названием.

Используйте функцию отслеживания времени выполнения операций в React Profiler до и после изменения состояния; сохраняйте отчет о различиях в PR для проверки.

Серверные компоненты и клиентские острова меняют местоположение дерева, но правила распространения изменений по-прежнему применяются на клиентском острове.

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

Разделение кода на уровне маршрутов сокращает размер дерева, за который вы платите при первой отрисовке; сочетайте это с локальным состоянием, чтобы сохранить легкость навигации.

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

Владение документом: какая команда владеет состоянием той или иной поддеревья. Общие глобальные хранилища вновь создают проблему широкого распространения изменений, только под другим названием.

Используйте функцию отслеживания времени выполнения операций в React Profiler до и после изменения состояния; сохраняйте отчет о различиях в PR для проверки.

Серверные компоненты и клиентские острова меняют местоположение дерева, но правила распространения изменений по-прежнему применяются на клиентском острове.

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

Разделение кода на уровне маршрутов сокращает размер дерева, за который приходится платить при первой отрисовке; сочетайте это с локальным состоянием, чтобы сохранить легкость навигации.

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

Владение документом: какая команда владеет состоянием той или иной поддеревья. Общие глобальные хранилища вновь создают проблему широкого распространения изменений, только под другим названием.

Используйте функцию отслеживания времени выполнения операций в React Profiler до и после изменения состояния; сохраняйте отчет о различиях в PR для проверки.

Серверные компоненты и клиентские острова меняют местоположение дерева, но правила распространения изменений по-прежнему применяются на клиентском острове.

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

Разделение кода на уровне маршрутов сокращает размер дерева, за который вы платите при первой отрисовке; сочетайте это с локальным состоянием, чтобы сохранить легкость навигации.

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

Владение документом: какая команда владеет состоянием той или иной поддеревья. Общие глобальные хранилища вновь создают проблему широкого распространения изменений, только под другим названием.

Используйте функцию отслеживания времени выполнения операций в React Profiler до и после изменения состояния; сохраняйте отчет о различиях в PR для проверки.

Серверные компоненты и клиентские острова меняют местоположение дерева, но правила распространения изменений по-прежнему применяются на клиентском острове.

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

Разделение кода на уровне маршрутов сокращает размер дерева, за который вы платите при первой отрисовке; сочетайте это с локальным состоянием, чтобы сохранить легкость навигации.

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

Полученные данные должны находиться в селекторах или запоминаемых дочерних элементах, а не отражаться в состоянии соседних элементов, что приводит к увеличению количества отрисовок.

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

Функции конкурентного выполнения помогают справиться с срочными задачами, но они не могут исправить «божественный компонент», контролирующий все поля сложного мастера.

Тактика миграции: с каждым PR перемещайте один лист «острова состояния» к корням с использованием инструмента профилирования до и после изменений.

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

Полученные данные должны находиться в селекторах или запоминаемых дочерних элементах, а не отражаться в состоянии соседних элементов, что приводит к увеличению количества отрисовок.

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

Функции параллельной обработки помогают срочно решить проблему, но они не могут исправить «божественный компонент», контролирующий все поля сложного мастера.

Тактика миграции: с каждым PR перемещать один узел состояния вглубь структуры с использованием инструмента профилирования до и после добавления изменений.

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

Полученные данные следует хранить в селекторах или в мемоизированных дочерних элементах, а не отражать в соседних узлах состояния, что приводит к увеличению количества отрисовок.

Визуализируйте структуру: рисуйте квадраты для элементов, контролирующих состояние, и стрелки для передаваемых им параметров. Широкое расширение ветвей от корня — это обычный признак проблемы.

Функции параллельной обработки помогают срочно решить проблему, но они не могут исправить «божественный компонент», контролирующий все поля сложного мастера.

Тактика миграции: с каждым PR перемещать один узел состояния вглубь структуры с использованием инструмента профилирования до и после добавления изменений.

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

Производные данные следует хранить в селекторах или в запомненных дочерних элементах, а не отражать в состоянии соседних элементов, что приводит к дополнительным рендерингам.

Визуализируйте структуру: рисуйте квадраты для элементов, управляющих состоянием, и стрелки для передаваемых им свойств. Широкое расширение ветвей от корня — это типичный признак проблемы.