useLoaderData для получения загруженных данных

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

Определение loader

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

const route = {
  path: "/posts/:postId",
  loader: async ({ params, context }) => {
    const response = await fetch(`https://api.example.com/posts/${params.postId}`);
    if (!response.ok) {
      throw new Response("Ошибка загрузки поста", { status: response.status });
    }
    return response.json();
  }
};

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

  • params — объект с параметрами маршрута, например postId.
  • context — глобальный объект контекста, передаваемый маршрутизатору.
  • loader может выбрасывать ошибки через throw new Response(), которые будут обработаны механизмами TanStack Router для ошибок.

Использование useLoaderData

После определения loader данные доступны внутри компонента через хук useLoaderData:

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

function PostPage() {
  const post = useLoaderData();

  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.body}</p>
    </div>
  );
}

Особенности работы хука:

  • useLoaderData автоматически подписывается на данные маршрута. Если при навигации данные обновятся, компонент перерендерится с новыми значениями.
  • Данные строго связаны с маршрутом: каждый маршрут хранит собственный результат loader.
  • Поддерживается типизация через TypeScript, что позволяет избежать ошибок при доступе к свойствам данных.

Асинхронность и состояние загрузки

TanStack Router сам обрабатывает асинхронность loader и предоставляет удобные механизмы для управления состоянием загрузки и ошибок. При необходимости можно использовать хуки useNavigation и useIsFetching для контроля процесса загрузки:

import { useNavigation, useIsFetching } from "@tanstack/router";

function PostPage() {
  const post = useLoaderData();
  const navigation = useNavigation();
  const isFetching = useIsFetching();

  if (navigation.state === "loading" || isFetching) {
    return <p>Загрузка данных...</p>;
  }

  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.body}</p>
    </div>
  );
}

Важно: useLoaderData не блокирует рендеринг; компонент может отображаться до того, как данные будут загружены, если используется серверная отрисовка или Suspense.

Работа с параметрами и контекстом

useLoaderData возвращает данные, зависящие от текущих параметров маршрута. Это позволяет динамически подгружать ресурсы:

const route = {
  path: "/users/:userId",
  loader: async ({ params }) => {
    return fetch(`https://api.example.com/users/${params.userId}`).then(res => res.json());
  }
};

function UserPage() {
  const user = useLoaderData();
  return <h2>{user.name}</h2>;
}

Если пользователь переходит с одного userId на другой, TanStack Router повторно вызовет loader и обновит данные, а useLoaderData автоматически вернёт новый результат.

Типизация данных

При использовании TypeScript можно указать тип возвращаемого loader и тем самым получить типизированный результат в useLoaderData:

interface Post {
  id: number;
  title: string;
  body: string;
}

const postRoute = {
  path: "/posts/:postId",
  loader: async ({ params }): Promise<Post> => {
    const res = await fetch(`/api/posts/${params.postId}`);
    return res.json();
  }
};

function PostPage() {
  const post = useLoaderData<Post>();
  return <h1>{post.title}</h1>;
}

Такой подход предотвращает ошибки при обращении к полям объекта и улучшает автодополнение в редакторе кода.

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

Если loader выбрасывает исключение, TanStack Router позволяет перехватить его через специальный маршрут с errorElement:

const postRoute = {
  path: "/posts/:postId",
  loader: async ({ params }) => {
    const res = await fetch(`/api/posts/${params.postId}`);
    if (!res.ok) throw new Response("Пост не найден", { status: 404 });
    return res.json();
  },
  errorElement: <p>Не удалось загрузить пост.</p>
};

useLoaderData в этом случае не вернёт данные, а компонент с errorElement будет отрисован автоматически.

Кэширование и повторное использование данных

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

Совместимость с Suspense

useLoaderData может быть интегрирован с React Suspense для отображения индикатора загрузки на уровне компонентов:

<Suspense fallback={<p>Загрузка...</p>}>
  <PostPage />
</Suspense>

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


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