TanStack Router предоставляет мощный и гибкий подход к маршрутизации в современных приложениях на JavaScript и TypeScript, включая эффективную работу с серверными данными. Основной принцип заключается в том, что маршруты могут асинхронно загружать данные до того, как компонент будет отрендерен, что позволяет создавать предсказуемые и отзывчивые интерфейсы.
Каждый маршрут в TanStack Router может содержать loader-функцию — специальный метод, который вызывается перед рендером компонента маршрута. Loader позволяет:
Пример определения маршрута с loader:
import { createRouter, createRouteConfig } from '@tanstack/router';
const rootRoute = createRouteConfig()
.path('/')
.component(RootComponent);
const userRoute = rootRoute.createRoute({
path: 'user/:userId',
component: UserComponent,
loader: async ({ params }) => {
const response = await fetch(`/api/users/${params.userId}`);
if (!response.ok) {
throw new Error('Ошибка при загрузке данных пользователя');
}
return response.json();
}
});
В этом примере loader получает объект
params, содержащий параметры маршрута, и возвращает данные
пользователя. TanStack Router автоматически передает эти данные в
компонент маршрута.
Данные, возвращенные loader-функцией, доступны внутри компонента
через хук useLoaderData. Этот хук обеспечивает строгую
типизацию и синхронизацию с маршрутом.
import { useLoaderData } from '@tanstack/router';
function UserComponent() {
const user = useLoaderData();
return (
<div>
<h1>{user.name}</h1>
<p>Email: {user.email}</p>
</div>
);
}
Преимущество такого подхода — компонент получает готовые
данные, и можно полностью отказаться от отдельного состояния
загрузки или эффектов useEffect для запроса данных.
Loader-функция принимает объект с параметрами:
params — параметры маршрута (например,
:userId);context — произвольные данные, переданные через
маршрутизатор;query — объект с query-параметрами URL.Пример использования query-параметров:
const searchRoute = rootRoute.createRoute({
path: 'search',
component: SearchComponent,
loader: async ({ query }) => {
const response = await fetch(`/api/search?q=${query.q}`);
return response.json();
}
});
В компоненте:
function SearchComponent() {
const results = useLoaderData();
return (
<ul>
{results.map(item => <li key={item.id}>{item.name}</li>)}
</ul>
);
}
TanStack Router поддерживает страницы ошибок и состояния загрузки на уровне маршрутов. Если loader выбрасывает исключение, маршрут может автоматически показать компонент ошибки:
const userRoute = rootRoute.createRoute({
path: 'user/:userId',
component: UserComponent,
loader: async ({ params }) => {
const response = await fetch(`/api/users/${params.userId}`);
if (!response.ok) {
throw new Response('Пользователь не найден', { status: 404 });
}
return response.json();
},
errorComponent: UserErrorComponent,
});
Компонент UserErrorComponent получит объект ошибки через
useRouteError() и сможет отображать соответствующее
сообщение пользователю.
Для отображения индикаторов загрузки можно использовать
useIsFetching или useTransition для
отслеживания состояния маршрутов.
TanStack Router позволяет кешировать результаты loader-функций, чтобы повторные переходы не выполняли лишние сетевые запросы:
loader автоматически кеширует данные по ключу маршрута
и параметрам;invalidate() или refetch() на маршруте.Пример принудительного обновления данных:
import { useRouter } from '@tanstack/router';
function RefreshButton() {
const router = useRouter();
return (
<button onCl ick={() => router.getRoute('user').refetch({ userId: '123' })}>
Обновить данные пользователя
</button>
);
}
TanStack Router полностью совместим с серверным рендерингом (SSR). Loader-функции можно вызывать на сервере для генерации HTML с уже загруженными данными. Это повышает производительность и улучшает SEO:
TanStack Router поддерживает строгую типизацию данных loader и параметров маршрута. Например:
interface User {
id: string;
name: string;
email: string;
}
const userRoute = rootRoute.createRoute<{ userId: string }, User>({
path: 'user/:userId',
component: UserComponent,
loader: async ({ params }) => {
const response = await fetch(`/api/users/${params.userId}`);
return response.json() as Promise<User>;
}
});
Типизация позволяет получать автодополнение и проверку типов в
useLoaderData():
const user = useLoaderData<typeof userRoute>();
Это гарантирует, что структура данных, возвращаемых сервером, будет строго соответствовать ожиданиям компонента.
Использование loader-функций в TanStack Router обеспечивает:
Такой подход позволяет строить масштабируемые приложения с комплексной маршрутизацией и асинхронной загрузкой данных, сохраняя высокую производительность и контроль над состоянием приложения.