TanStack Router предоставляет гибкую и высокопроизводительную систему маршрутизации для приложений на JavaScript, позволяя минимизировать лишние ререндеры компонентов. Основной подход к оптимизации заключается в разделении маршрутов и управлении состоянием так, чтобы изменения данных затрагивали только необходимые компоненты.
Один из ключевых инструментов уменьшения ререндеров — вложенные маршруты. Вместо того чтобы один корневой компонент рендерился при каждом изменении пути или данных, TanStack Router позволяет создавать дерево маршрутов, где каждый уровень отвечает за свою часть интерфейса.
const rootRoute = createRoute({
path: "/",
component: RootComponent,
children: [
{
path: "dashboard",
component: Dashboard,
},
{
path: "settings",
component: Settings,
},
],
});
В этом примере RootComponent не будет перерендериваться
при переходе между dashboard и settings, так
как оба маршрута находятся на одном уровне вложенности и не изменяют
состояние родителя.
loader и кеширование данныхTanStack Router поддерживает асинхронные загрузчики данных через
свойство loader. Loader вызывается только при
изменении маршрута, что позволяет загружать данные по необходимости и
предотвращать лишние ререндеры:
const dashboardRoute = createRoute({
path: "dashboard",
component: Dashboard,
loader: async () => {
const response = await fetch("/api/dashboard");
return response.json();
},
});
Для уменьшения ререндеров рекомендуется кешировать результаты
loader через встроенный cache или
сторонние решения, такие как TanStack Query, чтобы данные не загружались
заново при повторном посещении маршрута.
React.memo и useMemoДаже при правильной настройке маршрутов компоненты могут
ререндериться из-за изменений пропсов. Использование
React.memo и useMemo помогает предотвращать
лишние перерендеры дочерних компонентов:
const DashboardStats = React.memo(({ stats }) => {
return <StatsTable data={stats} />;
});
Для вычисляемых данных, зависящих от пропсов, useMemo
позволяет мемоизировать результат:
const filteredItems = useMemo(() => items.filter(item => item.active), [items]);
useMatch и
useNavigateTanStack Router предоставляет хуки useMatch и
useNavigate, которые позволяют компонентам отслеживать
изменения маршрута точечно, без перерендеров всего
дерева.
const match = useMatch("/dashboard");
if (match) {
// Компонент реагирует только на конкретный путь
}
Это обеспечивает локальное управление ререндером: компонент обновляется только если совпадает путь, а не при каждом изменении маршрута глобально.
Частая причина лишних ререндеров — смешение глобального состояния с состоянием маршрутов. Рекомендуется использовать отдельные менеджеры состояния (например, Zustand, Redux Toolkit) для глобальных данных, а TanStack Router — только для управления навигацией и загрузкой данных конкретных маршрутов.
const userStore = create((set) => ({
user: null,
setUser: (user) => set({ user }),
}));
Такое разделение гарантирует, что изменения в глобальном состоянии не вызывают перерендер всей иерархии маршрутов, а только компонентов, подписанных на эти данные.
TanStack Router поддерживает ленивую загрузку компонентов через
React.lazy и Suspense. Это позволяет рендерить
только необходимые компоненты для текущего маршрута:
const Dashboard = React.lazy(() => import("./Dashboard"));
const dashboardRoute = createRoute({
path: "dashboard",
component: () => (
<Suspense fallback={<div>Загрузка...</div>}>
<Dashboard />
</Suspense>
),
});
Благодаря этому подходу тяжелые компоненты не влияют на перерендер других маршрутов, что значительно снижает нагрузку на DOM и улучшает производительность.
Навигация по маршрутам TanStack Router может быть оптимизирована
через свойства preserveScroll,
preventScrollReset и defaultPending:
const settingsRoute = createRoute({
path: "settings",
component: Settings,
defaultPending: true,
});
Эти настройки предотвращают лишние перерендеры компонентов при переключении между маршрутами с одинаковой базовой структурой, сохраняя состояние интерфейса.
loader с кешированием
данных для асинхронной загрузки.Эти методы в совокупности позволяют эффективно использовать TanStack Router в крупных приложениях, снижая нагрузку на интерфейс и повышая отзывчивость.