Loader — это асинхронная функция, которая выполняется перед рендерингом маршрута и предназначена для получения данных, необходимых компоненту. В TanStack Router она играет ключевую роль при организации серверного рендеринга (SSR) и предварительной загрузки данных на сервере, обеспечивая согласованное состояние приложения до его передачи клиенту.
Loader вызывается при навигации на маршрут и может возвращать данные в любом виде: объект, массив, примитив. Возвращаемое значение передается в компонент через пропсы или через контекст маршрута. TanStack Router автоматически управляет асинхронностью, ожидая завершения loader’а перед рендерингом маршрута.
Пример структуры loader:
import { createRouter, createRoute } from '@tanstack/router'
const userRoute = createRoute({
path: '/user/:id',
loader: async ({ params, context }) => {
const response = await fetch(`https://api.example.com/users/${params.id}`)
if (!response.ok) throw new Error('Не удалось загрузить пользователя')
return response.json()
},
component: UserPage
})
В этом примере loader получает объект params, содержащий
параметры маршрута, и объект context, который может
использоваться для передачи глобальных зависимостей, например, токена
авторизации или клиента API.
На сервере loader’ы выполняются перед рендерингом HTML. Это позволяет:
Пример серверного рендеринга с использованием loader’ов:
import express from 'express'
import { renderToString } from 'react-dom/server'
import { RouterProvider } from '@tanstack/router'
import { router } from './router'
const app = express()
app.get('*', async (req, res) => {
try {
const match = await router.match(req.url)
// Выполнение loader'ов всех маршрутов, соответствующих текущему пути
const data = await match.loaders()
const html = renderToString(
<RouterProvider router={router} initialData={data} />
)
res.send(`<!DOCTYPE html>
<html>
<head><title>SSR с TanStack Router</title></head>
<body>
<div id="root">${html}</div>
</body>
</html>`)
} catch (err) {
res.status(500).send('Ошибка сервера')
}
})
Здесь метод match.loaders() выполняет все loader’ы,
относящиеся к маршрутам, которые соответствуют текущему URL.
Возвращаемые данные можно передать клиенту через
initialData для повторного использования без лишних
запросов.
Loader’ы могут получать контекст приложения. Обычно это объект с доступом к API, базе данных, сервисам аутентификации и другим глобальным зависимостям. Такой подход позволяет сделать loader полностью изолированным от компонента и облегчает тестирование.
const router = createRouter({
context: {
apiClient: new ApiClient(process.env.API_TOKEN)
}
})
const profileRoute = createRoute({
path: '/profile',
loader: async ({ context }) => {
return await context.apiClient.getProfile()
},
component: ProfilePage
})
Loader’ы могут выбрасывать ошибки, которые TanStack Router позволяет
перехватывать через специальные маршруты ошибок
(errorElement) или глобальный обработчик. Также можно
использовать состояния загрузки (pending) для отображения
индикаторов ожидания.
const userRoute = createRoute({
path: '/user/:id',
loader: async ({ params }) => {
const response = await fetch(`https://api.example.com/users/${params.id}`)
if (!response.ok) throw new Response('Пользователь не найден', { status: 404 })
return response.json()
},
component: UserPage,
errorElement: UserErrorPage
})
При возникновении ошибки роутер автоматически отобразит
errorElement, передав ему объект ошибки для детальной
обработки.
context
для независимости и тестируемости.Loader’ы в TanStack Router обеспечивают мощный механизм для асинхронного получения данных как на клиенте, так и на сервере, позволяя строить масштабируемые приложения с серверным рендерингом и согласованным состоянием.