Функции loader в React Router используются для
предварительной загрузки данных перед рендерингом компонента маршрута.
Это позволяет компонента сразу получать все необходимые данные, не
полагаясь на последующий useEffect или асинхронные вызовы
внутри компонента.
Синтаксис создания функции loader:
import { json } from "react-router-dom";
export async function exampleLoader({ params, request }) {
const response = await fetch(`/api/items/${params.id}`);
if (!response.ok) {
throw json({ message: "Ошибка при загрузке данных" }, { status: 500 });
}
const data = await response.json();
return data;
}
Параметры функции:
params — объект с параметрами маршрута, например
id из URL /items/:id.request — объект Request аналогичный
стандартному Fetch API, содержащий информацию о
запросе.context — опциональный объект, доступный в
маршрутизаторе через RouterProvider.Возвращаемые значения:
Функция может возвращать:
useLoaderData в компоненте маршрута.redirect или ошибкой через
throw json() для обработки ошибок маршрута.useLoaderDataПосле того как функция loader возвращает данные, они
становятся доступными в компоненте с помощью хука
useLoaderData:
import { useLoaderData } from "react-router-dom";
function ItemDetail() {
const item = useLoaderData();
return (
<div>
<h2>{item.name}</h2>
<p>{item.description}</p>
</div>
);
}
useLoaderData гарантирует, что компонент получит все
данные синхронно, когда маршрутизатор завершит выполнение
loader.
Функции loader отлично подходят для работы с
асинхронными запросами, такими как fetch, запросы к GraphQL
или обращения к базе данных.
Пример с обработкой ошибок:
import { redirect, json } from "react-router-dom";
export async function protectedLoader({ request }) {
const token = localStorage.getItem("authToken");
if (!token) {
return redirect("/login");
}
const response = await fetch("/api/protected", {
headers: { Authorization: `Bearer ${token}` },
});
if (!response.ok) {
throw json({ message: "Доступ запрещен" }, { status: 403 });
}
return response.json();
}
Здесь показано:
redirect).throw json()), которую можно отловить через
ErrorBoundary маршрута.Функции loader имеют доступ к динамическим сегментам URL
через params.
export async function userLoader({ params }) {
const response = await fetch(`/api/users/${params.userId}`);
return response.json();
}
Если маршрут определен как /users/:userId,
params.userId будет содержать значение из URL.
contextКонтекст позволяет передавать глобальные объекты или функции в loader без импорта напрямую в каждый модуль.
// App.js
import { createBrowserRouter, RouterProvider } from "react-router-dom";
const router = createBrowserRouter(routes, { context: { apiClient } });
export default function App() {
return <RouterProvider router={router} />;
}
// loader.js
export async function someLoader({ context }) {
const data = await context.apiClient.getData();
return data;
}
deferReact Router 6.4+ позволяет использовать defer, чтобы
частично загружать данные:
import { defer } from "react-router-dom";
export function deferredLoader() {
return defer({
user: fetch("/api/user").then(res => res.json()),
posts: fetch("/api/posts").then(res => res.json()),
});
}
Компонент может использовать useLoaderData и работать с
асинхронными свойствами через <Suspense>:
const data = useLoaderData();
<Suspense fallback={<p>Загрузка...</p>}>
<Await resolve={data.posts}>
{(posts) => <PostsList posts={posts} />}
</Await>
</Suspense>
defer помогает не блокировать рендер всего маршрута,
если часть данных загружается медленно.
Ошибки и редиректы в loader можно обрабатывать на уровне маршрута,
используя специальные свойства errorElement и
loader вместе с redirect.
const router = createBrowserRouter([
{
path: "/dashboard",
loader: dashboardLoader,
element: <Dashboard />,
errorElement: <DashboardError />,
},
]);
loader может выбросить ошибку или сделать
redirect.errorElement автоматически отобразится при ошибке, без
необходимости обрабатывать её внутри компонента.json() для формирования ошибок с кодом
статуса.defer при загрузке больших данных, чтобы не
блокировать UI.params и request для
предотвращения некорректных запросов.context для передачи общих
сервисов, таких как API-клиенты или настройки авторизации.Функции loader становятся ядром современной
маршрутизации в React Router, позволяя строить реактивные приложения с
предзагрузкой данных и минимальной зависимостью от эффекта
рендеринга.