Скелетоны и placeholder’ы представляют собой ключевой механизм для улучшения пользовательского опыта при асинхронной загрузке данных в приложениях на базе TanStack Router. Они позволяют отображать временные элементы интерфейса до получения фактического контента, снижая ощущение “зависания” страницы и повышая отзывчивость приложения.
TanStack Router поддерживает асинхронные маршруты через загрузку
данных в loader-ах. При этом компонент маршрута может
отображаться до завершения загрузки данных. Без скелетонов пользователь
видит пустую страницу или стандартный индикатор загрузки, что негативно
сказывается на UX.
import { createRouter, createRouteConfig } from '@tanstack/router'
const routeConfig = createRouteConfig()
.createRoute({
path: '/profile',
component: ProfilePage,
loader: async () => {
const user = await fetch('/api/user').then(res => res.json())
return { user }
},
})
const router = createRouter({ routeConfig })
В этом примере ProfilePage рендерится после завершения
loader. Если загрузка данных занимает несколько секунд,
пользователь видит пустое пространство. Решением служат скелетоны.
Скелетон — это компонент, имитирующий форму будущего
контента. В TanStack Router можно реализовать скелетон внутри маршрута,
используя Suspense и React.lazy или отдельный
компонент placeholder’а:
function ProfileSkeleton() {
return (
<div className="profile-skeleton">
<div className="avatar-placeholder" />
<div className="line-placeholder short" />
<div className="line-placeholder long" />
</div>
)
}
Ключевые моменты при проектировании скелетонов:
TanStack Router предоставляет возможность отображать временный
контент до завершения загрузки loader через
Suspense:
import { RouterProvider } from '@tanstack/router'
import { Suspense } from 'react'
function App() {
return (
<RouterProvider router={router}>
<Suspense fallback={<ProfileSkeleton />}>
<ProfilePage />
</Suspense>
</RouterProvider>
)
}
Особенности подхода:
Suspense блокирует отображение основного компонента до
завершения промиса, заданного в loader.fallback рендерит скелетон, позволяя пользователю
видеть визуальный каркас страницы.Для сложных страниц с множеством секций имеет смысл использовать локальные placeholder’ы, а не один глобальный скелетон. Это повышает отзывчивость интерфейса:
function ProfileDetails({ user }) {
return (
<div>
<Suspense fallback={<LineSkeleton />}>
<UserBio user={user} />
</Suspense>
<Suspense fallback={<LineSkeleton />}>
<UserPosts userId={user.id} />
</Suspense>
</div>
)
}
Преимущества локальных placeholder’ов:
TanStack Router поддерживает условные рендеры скелетонов на основе состояния данных. Например, если часть данных уже загружена, можно отобразить скелетон только для оставшихся частей:
function UserPostsSection({ posts }) {
if (!posts) {
return <PostsSkeleton count={5} />
}
return <PostsList posts={posts} />
}
Рекомендации:
Несмотря на визуальные преимущества, чрезмерное использование скелетонов может замедлить рендеринг, особенно на мобильных устройствах. Оптимизация включает:
TanStack Router позволяет кэшировать результаты loader.
Это означает, что при навигации между маршрутами можно отображать
скелетоны только при первой загрузке данных:
const routeConfig = createRouteConfig()
.createRoute({
path: '/profile',
component: ProfilePage,
loader: async () => {
return await fetchUserData()
},
onLoadCache: (data) => data, // повторное использование данных без скелетона
})
Такой подход сокращает количество визуальных переходов между скелетоном и реальным контентом, создавая плавный UX.
Комбинируя глобальные и локальные скелетоны, можно построить страницу профиля с несколькими асинхронными секциями:
function ProfilePage() {
const { user } = useLoaderData()
return (
<div className="profile-page">
<Suspense fallback={<ProfileHeaderSkeleton />}>
<ProfileHeader user={user} />
</Suspense>
<Suspense fallback={<PostsSkeleton count={3} />}>
<UserPosts userId={user.id} />
</Suspense>
<Suspense fallback={<FriendsSkeleton count={4} />}>
<UserFriends userId={user.id} />
</Suspense>
</div>
)
}
Каждая секция загружается независимо, а пользователь видит постоянный визуальный каркас, что значительно улучшает восприятие скорости работы приложения.
Скелетоны и placeholder’ы в TanStack Router — это не просто декоративный элемент, а инструмент для управления асинхронностью и отзывчивостью интерфейса, обеспечивающий плавную и предсказуемую загрузку данных.