Перейти к содержимому

14. Router: loaders и данные

Лоадеры — функции, которые загружают данные до рендеринга компонента маршрута. Это ключевое отличие от useQuery внутри компонента: данные готовы к моменту первого рендеринга.

export const Route = createFileRoute('/users/$userId')({
loader: async ({ params }) => {
const user = await fetchUser(params.userId)
return user // Данные доступны через Route.useLoaderData()
},
component: UserDetail,
})
function UserDetail() {
const user = Route.useLoaderData()
// user: User — полностью типизировано, никогда не undefined
return <h1>{user.name}</h1>
}

Лучшая практика — использовать queryClient.ensureQueryData в лоадере:

export const Route = createFileRoute('/users/$userId')({
loader: ({ context: { queryClient }, params }) =>
queryClient.ensureQueryData({
queryKey: ['user', params.userId],
queryFn: () => fetchUser(params.userId),
}),
component: UserDetail,
})
function UserDetail() {
// Данные уже в кэше Query — useQuery вернёт их мгновенно
const { data: user } = useQuery({
queryKey: ['user', Route.useParams().userId],
queryFn: () => fetchUser(Route.useParams().userId),
})
}

beforeLoad выполняется до лоадера. Используется для проверки авторизации, редиректов:

export const Route = createFileRoute('/dashboard')({
beforeLoad: ({ context }) => {
if (!context.auth.isAuthenticated) {
throw redirect({ to: '/login' })
}
},
loader: () => fetchDashboardData(),
})

По умолчанию лоадеры вложенных маршрутов выполняются параллельно:

/users → loader: fetchUsers() ─┐
/$userId → loader: fetchUser(id) ─┤ Параллельно!
/posts → loader: fetchUserPosts() ─┘

Чтобы дождаться родительского лоадера:

loader: async ({ params, context }) => {
const user = await context.loaderData // Данные родительского лоадера
return fetchPostsForUser(user.id)
}
export const Route = createFileRoute('/users')({
loader: getUsers,
pendingComponent: () => <Spinner />,
errorComponent: ({ error }) => <ErrorMessage error={error} />,
component: UsersList,
})

Контроль как часто перезагружаются данные лоадера:

export const Route = createFileRoute('/users')({
loader: getUsers,
staleTime: 1000 * 60, // Данные актуальны 1 минуту
})