Lazy loading компонентов маршрутов

Lazy loading в TanStack Router позволяет загружать компоненты маршрутов по требованию, что снижает первоначальный размер бандла и ускоряет время первого рендера приложения. Основная идея заключается в том, чтобы импортировать компонент только тогда, когда пользователь переходит на соответствующий маршрут.


Использование React.lazy и Suspense

В TanStack Router можно интегрировать стандартные возможности React для ленивой загрузки компонентов:

import React, { Suspense } from 'react';
import { RouterProvider, createRouter, Route } from '@tanstack/router';

const Home = React.lazy(() => import('./pages/Home'));
const About = React.lazy(() => import('./pages/About'));

const router = createRouter({
  routeConfig: [
    {
      path: '/',
      component: () => (
        <Suspense fallback={<div>Загрузка...</div>}>
          <Home />
        </Suspense>
      ),
    },
    {
      path: '/about',
      component: () => (
        <Suspense fallback={<div>Загрузка...</div>}>
          <About />
        </Suspense>
      ),
    },
  ],
});

export default function App() {
  return <RouterProvider router={router} />;
}

Ключевые моменты:

  • React.lazy возвращает компонент, который React загружает асинхронно.
  • Suspense обеспечивает отображение fallback-контента, пока компонент загружается.
  • Каждому ленивому маршруту нужен свой <Suspense> для контроля загрузки именно этого компонента.

Ленивые маршруты с TanStack Router v6+

TanStack Router предоставляет API для более «родного» подхода к ленивой загрузке через свойства маршрута getComponent. Это позволяет создавать маршруты, которые подгружают свои компоненты только при необходимости.

import { createRouter, RouterProvider } from '@tanstack/router';

const router = createRouter({
  routeConfig: [
    {
      path: '/',
      getComponent: async () => {
        const module = await import('./pages/Home');
        return module.default;
      },
    },
    {
      path: '/about',
      getComponent: async () => {
        const module = await import('./pages/About');
        return module.default;
      },
    },
  ],
});

export default function App() {
  return <RouterProvider router={router} />;
}

Особенности getComponent:

  • Позволяет избегать оборачивания маршрута в <Suspense> вручную.
  • Возвращает промис с компонентом, который TanStack Router сам обработает.
  • Отлично подходит для крупных приложений с множеством маршрутов и разделением кода.

Обработка ошибок при ленивой загрузке

Для асинхронных компонентов необходимо предусматривать обработку ошибок загрузки:

const ErrorBoundary = ({ error }) => (
  <div>Ошибка при загрузке: {error.message}</div>
);

const router = createRouter({
  routeConfig: [
    {
      path: '/dashboard',
      getComponent: async () => {
        try {
          const module = await import('./pages/Dashboard');
          return module.default;
        } catch (error) {
          return () => <ErrorBoundary error={error} />;
        }
      },
    },
  ],
});

Рекомендации:

  • Использовать отдельный компонент для отображения ошибок.
  • Можно объединять с <Suspense> для показа индикатора загрузки, пока идет асинхронный импорт.

Lazy loading вложенных маршрутов

TanStack Router поддерживает ленивую загрузку даже для вложенных маршрутов. Это особенно полезно для крупных секций приложения, например, административной панели.

const router = createRouter({
  routeConfig: [
    {
      path: '/admin',
      getComponent: async () => {
        const module = await import('./pages/admin/AdminLayout');
        return module.default;
      },
      children: [
        {
          path: 'users',
          getComponent: async () => {
            const module = await import('./pages/admin/Users');
            return module.default;
          },
        },
        {
          path: 'settings',
          getComponent: async () => {
            const module = await import('./pages/admin/Settings');
            return module.default;
          },
        },
      ],
    },
  ],
});

Важные моменты:

  • Каждый вложенный маршрут может иметь собственный ленивый компонент.
  • TanStack Router динамически подгружает только те маршруты, которые нужны пользователю в данный момент.
  • Можно комбинировать ленивую загрузку с preload для ускорения переходов по часто используемым маршрутам.

Предзагрузка (Preloading) компонентов

Для улучшения UX и уменьшения времени ожидания переходов можно использовать метод preload:

const AboutRoute = {
  path: '/about',
  getComponent: async () => {
    const module = await import('./pages/About');
    return module.default;
  },
};

AboutRoute.preload(); // инициирует загрузку заранее

Преимущества предзагрузки:

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

Рекомендации по структуре проекта

  1. Разделять компоненты по функциональным модулям.
  2. Для крупных страниц использовать getComponent вместо статического импорта.
  3. Комбинировать Suspense и ErrorBoundary для управления состояниями загрузки и ошибок.
  4. Подумать о стратегиях предзагрузки для часто посещаемых маршрутов.

Эти подходы обеспечивают гибкость, оптимизацию загрузки и структурированное управление маршрутами в больших приложениях на React с использованием TanStack Router.