В 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 типы загружаемых данных могут быть строго определены, что повышает безопасность кода:
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 мощным инструментом для построения реактивных, типобезопасных приложений с эффективной асинхронной загрузкой данных и управлением состоянием маршрутов.