Доступ к загруженным данным в компонентах

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

Свойство loader

Каждый маршрут в TanStack Router может иметь свой loader — функцию, которая выполняется до монтирования компонента маршрута. Функция loader может быть асинхронной и возвращать любые данные, которые потребуются компоненту. Пример использования:

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

const userRoute = createRouteConfig({
  path: '/user/:userId',
  loader: async ({ params }) => {
    const response = await fetch(`/api/users/${params.userId}`);
    if (!response.ok) throw new Error('Failed to fetch user');
    return response.json();
  },
  component: UserComponent,
});

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

Хук useLoaderData

После того как loader завершил выполнение, данные можно получить с помощью хука useLoaderData. Он обеспечивает типобезопасный доступ к загруженным данным:

import { useLoaderData } from '@tanstack/router';

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

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

Работа с вложенными маршрутами

Вложенные маршруты наследуют контекст данных родительских маршрутов. Если родительский маршрут загружает данные через loader, дочерний маршрут может их использовать без повторного запроса. Пример:

const dashboardRoute = createRouteConfig({
  path: '/dashboard',
  loader: async () => ({ stats: await fetchStats() }),
  component: DashboardLayout,
  children: [
    createRouteConfig({
      path: 'reports',
      component: Reports,
    }),
  ],
});

В компоненте Reports можно получить доступ к данным родителя:

import { useLoaderData, useParentLoaderData } from '@tanstack/router';

function Reports() {
  const parentData = useParentLoaderData();
  const stats = parentData.stats;

  return <div>Отчёты по статистике: {stats.total}</div>;
}

Хук useParentLoaderData обеспечивает прямой доступ к данным ближайшего родительского маршрута с loader.

Кэширование и реактивность

TanStack Router поддерживает кэширование данных loader. Если маршрут уже был посещён и данные не изменились, повторное обращение к loader не выполняется. Для управления этим поведением можно использовать:

  • loader с ключом зависимостей;
  • явное обновление данных через методы маршрутизатора, такие как router.refresh().
function RefreshButton() {
  const router = useRouter();

  return (
    <button onCl ick={() => router.refresh()}>Обновить данные</button>
  );
}

Это позволяет компонентам оставаться реактивными и синхронизированными с серверными данными без лишних сетевых запросов.

Обработка ошибок загрузки данных

Если loader выбрасывает ошибку, TanStack Router позволяет определить компонент для отображения ошибок через errorComponent:

const userRoute = createRouteConfig({
  path: '/user/:userId',
  loader: async ({ params }) => {
    const response = await fetch(`/api/users/${params.userId}`);
    if (!response.ok) throw new Error('Пользователь не найден');
    return response.json();
  },
  component: UserComponent,
  errorComponent: UserError,
});

В UserError можно получить объект ошибки через useRouteError:

import { useRouteError } from '@tanstack/router';

function UserError() {
  const error = useRouteError();
  return <div>Ошибка загрузки пользователя: {error.message}</div>;
}

Таким образом, TanStack Router обеспечивает полный цикл работы с асинхронными данными: загрузка, кэширование, доступ внутри компонентов и обработка ошибок.

Поддержка TypeScript

При использовании TypeScript типы загружаемых данных могут быть строго определены, что повышает безопасность кода:

interface User {
  id: string;
  name: string;
  email: string;
}

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

В компоненте useLoaderData<User>() гарантирует, что возвращаемые данные соответствуют интерфейсу User, исключая ошибки типов на этапе компиляции.

Динамическая загрузка данных

TanStack Router позволяет обновлять данные маршрута при изменении параметров без размонтирования компонента. Для этого loader вызывается повторно при изменении params, search или других наблюдаемых значений маршрута. Это особенно полезно для страниц с фильтрацией или пагинацией.

const postsRoute = createRouteConfig({
  path: '/posts/:page',
  loader: async ({ params }) => fetchPosts(params.page),
  component: Posts,
});

При переходе с /posts/1 на /posts/2 компонент Posts не размонтируется, а loader автоматически загрузит новые данные для второго номера страницы.


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