Скорость реакции начинается с организации дерева компонентов.
Повторная обработка — не враг, а проблема заключается в широком распространении данных по всей системе. Сначала переместите источники к листовым узлам, прежде чем использовать микро-запоминание.
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 перемещать один узел состояния вглубь структуры с использованием инструмента профилирования до и после добавления изменений.
Провайдеры, которые обновляются при каждом нажатии клавиши, должны охватывать только те компоненты-потребители, которым нужна такая частота обновлений, а не всю структуру страницы.
Производные данные следует хранить в селекторах или в запомненных дочерних элементах, а не отражать в состоянии соседних элементов, что приводит к дополнительным рендерингам.
Визуализируйте структуру: рисуйте квадраты для элементов, управляющих состоянием, и стрелки для передаваемых им свойств. Широкое расширение ветвей от корня — это типичный признак проблемы.