Практические советы: как я оптимизировал медленное приложение на React, не переписывая его
Пошаговое руководство по практическим советам: как я оптимизировал медленное приложение на React, не переписывая его: контракты, проверки и слоты для вставки кода для команд, использующих эту паттерн-архитектуру.
Используйте это как переработанную версию идей из статьи «Как я оптимизировал медленное приложение на React без его переписывания» для операторов: четкие этапы, упорядоченные блоки кода и записи о восстановлении, сохраняющиеся при передаче задачи. Этап Обзора работает наилучшим образом, если рассматривать его как измеримую основу. Соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объема работ. Рассматривайте этот этап как контракт между входными данными и проверенными результатами. Дайте названия создаваемым элементам, определите критерии успеха и не соглашайтесь на молчаливое частичное выполнение задачи.
Диагностика: поиск проблемы
Для определения стадии диагностики необходимо заранее оговорить входные данные, ответственного за выполнение шага и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Рядом с функциональными результатами следует записывать время выполнения и стоимость токенов или запросов. Отображение затрат с самого начала помогает избежать неожиданных счетов при переходе от демо-среды к общедоступным средам. Состояние следует размещать рядом с компонентом, ответственным за его изменение. Хранение всего в глобальном хранилище затрудняет выявление ошибок, связанных с временем выполнения.
1. React.memo: Самое простое решение
Для функции React memo The stage необходимо заранее определить входные данные, ответственного за выполнение шага и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Храните конфигурацию вне кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь код. Храните состояние рядом с компонентом, ответственным за его изменение. Размещение всего в глобальном хранилище затрудняет обнаружение ошибок, связанных с временем выполнения.
const ExpensiveComponent = React.memo(({ data, onUpdate }) => {
// Component logic
});
2. useMemo и useCallback: прекращение рекурсивных пересчётов
На этапах useMemo и useCallback необходимо заранее определить входные данные, ответственного за выполнение шага и критерии завершения перед внесением изменений в код. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Необходимо одновременно задокументировать успешный и восстановительный сценарии работы. Повторные попытки, проверки человеком и обработка неработоспособных сообщений являются частью продукта, а не этапом последующей доработки. Храните состояние вместе с компонентом, ответственным за его изменение. Перемещение всего в глобальный хранилище затрудняет выявление проблем с временем выполнения. На этапах useMemo и useCallback необходимо заранее определить входные данные, ответственного за выполнение шага и критерии завершения перед внесением изменений в код. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Рассматривайте этот этап как контракт между входными данными и проверенными выходными результатами. Дайте названия элементам, определите критерии успеха и не допускайте безответственного частичного завершения работы.
const computedStats = useMemo(() => {
return expensiveAggregation(data);
}, [data]);
const handleUpdate = useCallback((id) => {
updateItem(id);
}, []);
3. useTransition: Приоритет взаимодействия с пользователем
При работе над этапом 3 useTransition «Приоритет взаимодействия с пользователем» сначала запишите условия работы: необходимые входные данные, сигнал о успешном выполнении и действия при частичной неудаче. Такой чек-лист поможет сохранять честность при последующих изменениях кода. Рядом с функциональными результатами записывайте время выполнения и стоимость токенов или запросов. Отображение затрат с самого начала предотвращает неожиданные расходы при переходе с демо-среды в общедоступные среды. Рассматривайте эффекты как синхронизацию с внешним миром, а не как замену вычисляемых значений во время отрисовки.
const [isPending, startTransition] = useTransition();
const handleSearch = (term) => {
startTransition(() => {
setSearchTerm(term);
// Filtering happens in the background
});
};
4. useDeferredValue: Снижение нагрузки на ресурсоемкую отрисовку
При работе над этапом 4 «Сглаживание с использованием useDeferredValue» сначала запишите условия работы: необходимые входные данные, сигнал о успешном выполнении и что происходит при частичной неудаче. Такой чек-лист поможет избежать ошибок при последующих изменениях кода. Храните конфигурацию вне кода приложения. Файлы с настройками окружения, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь код. Рассматривайте эффекты как синхронизацию с внешним миром, а не как замену вычисляемых значений во время отрисовки.
const deferredData = useDeferredValue(data);
// Chart receives deferredData and updates only when React has idle time
5. Виртуализация: отрисовка только видимого
При работе над этапом «Только виртуализация и рендеринг» сначала запишите условия взаимодействия: необходимые входные данные, сигнал о успешном выполнении и действия при частичной неудаче. Такой список поможет сохранять честность при последующих изменениях кода. Документируйте как успешный, так и восстановительный пути выполнения. Повторные попытки, проверки человеком и обработка неработоспособных сообщений являются частью продукта, а не этапом последующей доработки. Рассматривайте эффекты как синхронизацию с внешним миром, а не как замену получаемых в процессе рендеринга значений. При работе над этапом «Только виртуализация и рендеринг» сначала запишите условия взаимодействия: необходимые входные данные, сигнал о успешном выполнении и действия при частичной неудаче. Такой список поможет сохранять честность при последующих изменениях кода. Рассматривайте этот этап как договоренность между входными данными и проверенными выходными результатами. Дайте названия соответствующим элементам, определите критерии успеха и не допускайте безусловного частичного завершения работы.
import { FixedSizeList } from 'react-window';
const Row = ({ index, style }) => (
<div style={style}>
{data[index].name}
</div>
);
<FixedSizeList
height={400}
itemCount={data.length}
itemSize={35}
width="100%"
>
{Row}
</FixedSizeList>
6. Задержанная загрузка: разделение кода по маршрутам
Шестой этап реализации задержанной загрузки работает наилучшим образом, если рассматриваться как измеряемая часть процесса. Сначала необходимо зафиксировать один идеальный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию, прежде чем расширять объем работ. Регистрируйте время выполнения и затраты на обработку токенов или запросов вместе с функциональными результатами. Отслеживание затрат на раннем этапе помогает избежать неожиданных расходов при переходе с демо-среды в общедоступные среды. Старайтесь сохранять низкие затраты на отрисовку и откладывайте ресурсоемкие вычисления с использованием мемоизации только после их измерения. Преждевременное применение мемоизации может скрыть ошибки, связанные с устаревшими данными.
const Dashboard = lazy(() => import('./views/Dashboard'));
const Analytics = lazy(() => import('./views/Analytics'));
function App() {
return (
<Suspense fallback={<Loading />}>
<Routes>
<Route path="/" element={<Dashboard />} />
<Route path="/analytics" element={<Analytics />} />
</Routes>
</Suspense>
);
}
7. useMemoizedSelector: оптимизация управления состоянием
Система управления состоянием 7 useMemoizedSelector работает наилучшим образом, если рассматривать её как измеримую структуру. Соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объёма работы. Храните конфигурацию вне кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь код. Старайтесь сделать процесс отрисовки простым и выполняйте затратные вычисления только после измерения эффективности с использованием мемоизации. Преждевременная мемоизация может скрыть ошибки, связанные с устаревшими параметрами.
import { createSelector } from '@reduxjs/toolkit';
const selectFilteredData = createSelector(
(state) => state.items,
(state) => state.filterTerm,
(items, term) => items.filter(item =>
item.name.toLowerCase().includes(term.toLowerCase())
)
);
// In component:
const filteredData = useSelector(selectFilteredData);
Цифры: до и после
Этап «The Numbers Before» работает наилучшим образом, когда его рассматривают как измеримую среду. Соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объёма работ. Документируйте как успешный, так и восстановительный пути выполнения. Повторные попытки, проверки человеком и обработка неработающих сообщений являются частью продукта, а не этапом последующей доработки. Сохраняйте низкую стоимость процесса генерации результатов и откладывайте дорогостоящие операции на этап мемоизации только после проведения измерений; преждевременная мемоизация может скрыть ошибки в устаревших данных. Этап «The Numbers Before» работает наилучшим образом, когда его рассматривают как измеримую среду. Соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объёма работ. Рассматривайте этот этап как контракт между входными данными и проверенными выходными результатами. Дайте названия соответствующим элементам, определите критерии успеха и не допускайте молчаливого частичного завершения работы.
Изменение образа мышления
На этапе смены образа мышления необходимо заранее определить входные данные, ответственного за выполнение шага и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Рядом с функциональными результатами следует записывать время выполнения и стоимость токенов или запросов. Отображение затрат с самого начала помогает избежать неожиданных счетов при переходе от демо-среды к общедоступным средам. Состояние следует хранить в том же компоненте, который отвечает за его изменение. Хранение всего в глобальном хранилище затрудняет выявление ошибок, связанных с временем выполнения.
Итог
На этапе The Bottom Line необходимо заранее определить входные данные, ответственного за выполнение шага и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Конфигурацию следует хранить отдельно от кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь кодовый граф. Состояние следует хранить рядом с компонентом, ответственным за его изменение. Хранение всего в глобальном хранилище затрудняет выявление ошибок, связанных с временем выполнения.
Чек-лист операционной деятельности
При работе над чек-листом операционной деятельности сначала необходимо описать условия работы: требуемые входные данные, сигнал о успешном выполнении и действия при частичной неудаче. Этот чек-лист помогает сохранять честность последующих изменений в коде.
Лучше использовать небольшие, тестируемые единицы вместо обширных скриптов. Когда какой-то шаг терпит неудачу, ошибка должна указывать на конкретную ответственность, а не на запутанную цепочку операций.
Рассматривайте эффекты как синхронизацию с внешним миром, а не как замену значений, получаемых в процессе отрисовки.
Фиксируйте версии зависимостей и записывайте хэш изображения, с использованием которого выполнялась демонстрация. Воспроизводимость важнее коллективных знаний.
Рассматривайте этот этап как контракт между входными данными и проверенными выходными результатами. Давайте названия результатам работы, определим критерии успеха и не допускайте молчаливого частичного выполнения задачи.
Рассматривайте эффекты как синхронизацию с внешним миром, а не как замену значений, получаемых в процессе отрисовки.
Перед внедрением данной стек-технологии необходимо заморозить версии, сделать копию «золотого» протокола действий для критически важных этапов и уточнить шаги отката. В совместных средах требуются ограничения на частоту запросов, проверки принадлежности пользователя и четко определенный ответственный за обновление секретов. Лучше выбирать надежность, даже если она кажется скучной, чем креативные одноразовые демонстрации.
Примечание для d6a7f4e83dda: не храните ключи поставщика в репозитории, установите лимит токенов на одну сессию и сохраняйте протоколы действий рядом с фикстурами для оценки, чтобы последующие замены моделей оставались сопоставимыми.