Pending-компоненты в TanStack Router обеспечивают возможность отображения промежуточного состояния интерфейса, когда данные ещё загружаются или выполняется асинхронная операция перед рендером основной страницы. В современном веб-программировании это ключевой инструмент для создания отзывчивых и плавных интерфейсов без “мерцания” и резкой смены контента.
В TanStack Router маршруты могут содержать асинхронные загрузчики
данных через loader. Каждый loader возвращает
либо данные сразу, либо промис, который разрешается после завершения
асинхронной операции:
import { createRouter, Route } from '@tanstack/router';
const userRoute = new Route({
path: '/user/:id',
loader: async ({ params }) => {
const response = await fetch(`/api/user/${params.id}`);
return response.json();
},
component: UserPage,
});
Если loader возвращает промис, рендеринг компонента
будет отложен до завершения промиса. Здесь и вступает в работу
Pending-компонент, который позволяет показывать
пользовательский интерфейс во время ожидания данных.
Pending-компонент — это отдельный React-компонент, который рендерится
автоматически в момент ожидания загрузки данных. Его подключение
осуществляется через свойство pendingComponent
маршрута:
const userRoute = new Route({
path: '/user/:id',
loader: async ({ params }) => {
const response = await fetch(`/api/user/${params.id}`);
return response.json();
},
component: UserPage,
pendingComponent: () => <div>Загрузка данных пользователя...</div>,
});
Важное свойство: Pending-компонент не получает пропсы от маршрута напрямую. Его задача — отображение состояния ожидания, а не работа с данными.
TanStack Router позволяет гибко управлять тем, как долго
Pending-компонент показывается. Для этого используется опция
pendingMs, задающая минимальное время отображения:
const userRoute = new Route({
path: '/user/:id',
loader: async ({ params }) => {
const response = await fetch(`/api/user/${params.id}`);
return response.json();
},
component: UserPage,
pendingComponent: () => <div>Загрузка...</div>,
pendingMs: 300, // Показывать не меньше 300 мс
});
Это предотвращает “мерцание” интерфейса, если данные загружаются слишком быстро.
Pending-компоненты работают и с вложенными маршрутами. Вложенный маршрут может иметь собственный Pending-компонент, который будет отображаться отдельно от родительского:
const userPostsRoute = new Route({
path: 'posts',
loader: async ({ params }) => {
const response = await fetch(`/api/user/${params.id}/posts`);
return response.json();
},
component: UserPostsPage,
pendingComponent: () => <div>Загрузка постов...</div>,
});
const userRoute = new Route({
path: '/user/:id',
component: UserPage,
children: [userPostsRoute],
pendingComponent: () => <div>Загрузка информации пользователя...</div>,
});
В этом примере пока загружается основной маршрут
/user/:id, отображается один Pending-компонент, а при
переходе к /user/:id/posts показывается отдельный
Pending-компонент для постов.
TanStack Router предоставляет хук usePending, который
позволяет отслеживать состояние загрузки маршрута и создавать кастомные
Pending-компоненты:
import { usePending } from '@tanstack/router';
function UserPage() {
const pending = usePending();
return (
<div>
{pending ? <div>Данные загружаются...</div> : <UserData />}
</div>
);
}
usePending возвращает булево значение, которое меняется
на true, когда текущий маршрут находится в состоянии
ожидания асинхронных данных, и false после завершения
загрузки.
Pending-компоненты TanStack Router легко интегрируются с React
Suspense. Маршрут с Suspense позволяет рендерить асинхронные компоненты,
используя fallback, что делает Pending-компоненты и
Suspense полностью совместимыми:
import React, { Suspense } from 'react';
const UserData = React.lazy(() => import('./UserData'));
const userRoute = new Route({
path: '/user/:id',
component: () => (
<Suspense fallback={<div>Загрузка данных пользователя...</div>}>
<UserData />
</Suspense>
),
});
Это обеспечивает плавную загрузку даже для тяжёлых компонентов и поддерживает единообразный UX.
pendingMs), чтобы избежать мерцания
интерфейса.Pending-компоненты в TanStack Router — мощный инструмент для управления асинхронностью маршрутов и создания плавного пользовательского интерфейса, особенно в сложных приложениях с множеством вложенных страниц и динамических данных.