Определение loader для маршрута

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

Основы определения loader

Loader определяется в объекте маршрута через свойство loader. Он может быть асинхронной функцией, возвращающей данные напрямую, либо промис, который резолвится в объект данных:

import { createRouter, createRouteConfig } from '@tanstack/router'

const route = createRouteConfig({
  path: '/users/:userId',
  loader: async ({ params }) => {
    const response = await fetch(`/api/users/${params.userId}`);
    if (!response.ok) {
      throw new Error('Ошибка загрузки данных пользователя');
    }
    return response.json();
  },
  component: UserComponent,
});

В данном примере loader получает объект params, который содержит параметры маршрута (userId), и выполняет асинхронный запрос к API. Возвращаемые данные затем доступны компоненту через хук useLoaderData.

Аргументы loader

Loader вызывается с объектом контекста, который содержит следующие ключи:

  • params — объект параметров маршрута (например, динамические сегменты пути).
  • search — объект с query-параметрами URL.
  • request — объект Request, если используется TanStack Router с поддержкой fetch API.
  • context — общий объект контекста, который можно передавать в router при его создании.

Пример использования query-параметров:

const searchRoute = createRouteConfig({
  path: '/search',
  loader: async ({ search }) => {
    const response = await fetch(`/api/search?q=${encodeURIComponent(search.q)}`);
    return response.json();
  },
  component: SearchComponent,
});

Ошибки и обработка

Loader может выбрасывать ошибки при неудачных запросах. TanStack Router предоставляет возможность обрабатывать такие ошибки через ErrorBoundary, прикрепленный к маршруту:

const route = createRouteConfig({
  path: '/posts/:id',
  loader: async ({ params }) => {
    const res = await fetch(`/api/posts/${params.id}`);
    if (!res.ok) {
      throw new Error('Пост не найден');
    }
    return res.json();
  },
  component: PostComponent,
  errorComponent: PostErrorComponent,
});

При возникновении ошибки рендерится компонент errorComponent, а сам компонент маршрута не отображается.

Оптимизация и кеширование

Loader можно оптимизировать, избегая лишних запросов и повторного рендера. TanStack Router поддерживает useLoaderData для получения данных без повторного вызова loader при переходе по маршруту, если данные не изменились:

import { useLoaderData } from '@tanstack/router'

function UserComponent() {
  const user = useLoaderData();
  return (
    <div>
      <h1>{user.name}</h1>
      <p>Email: {user.email}</p>
    </div>
  );
}

Асинхронные зависимости и параллельные загрузки

Loader может одновременно запускать несколько асинхронных запросов через Promise.all:

const dashboardRoute = createRouteConfig({
  path: '/dashboard',
  loader: async () => {
    const [userRes, statsRes] = await Promise.all([
      fetch('/api/user'),
      fetch('/api/stats')
    ]);
    const user = await userRes.json();
    const stats = await statsRes.json();
    return { user, stats };
  },
  component: DashboardComponent,
});

Типизация loader (TypeScript)

TanStack Router позволяет строго типизировать loader и возвращаемые данные:

type UserData = {
  id: string;
  name: string;
  email: string;
};

const userRoute = createRouteConfig({
  path: '/users/:id',
  loader: async ({ params }): Promise<UserData> => {
    const res = await fetch(`/api/users/${params.id}`);
    return res.json();
  },
  component: UserComponent,
});

Использование типизации повышает предсказуемость данных и предотвращает ошибки доступа к несуществующим полям в компоненте.

Сводка ключевых моментов

  • Loader выполняется до рендеринга компонента и возвращает необходимые данные.
  • Доступ к данным происходит через useLoaderData.
  • Аргументы loader: params, search, request, context.
  • Ошибки можно обрабатывать с помощью errorComponent.
  • Возможна параллельная загрузка данных и кеширование между переходами.
  • TypeScript обеспечивает строгую типизацию возвращаемых данных loader.

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