React Router предоставляет мощный инструмент для управления
асинхронными данными и обработкой ошибок на уровне маршрутов через хуки
useAsyncValue и
useAsyncError. Эти хуки используются в
связке с асинхронными загрузчиками данных, которые определяются для
маршрутов, что позволяет строить сложные, реактивные интерфейсы с
минимальной ручной работой по управлению состоянием загрузки и
ошибок.
useAsyncValue используется для
получения результата асинхронного загрузчика маршрута
(loader). Он возвращает значение, которое было возвращено
из функции загрузки маршрута после её успешного выполнения. Этот хук
облегчает работу с данными на уровне компонентов, связанных с маршрутом,
устраняя необходимость самостоятельно управлять состоянием загрузки и
ошибок.
Пример использования:
import { useAsyncValue } from "react-router-dom";
function UserProfile() {
const user = useAsyncValue();
return (
<div>
<h1>Профиль пользователя</h1>
<p>Имя: {user.name}</p>
<p>Email: {user.email}</p>
</div>
);
}
В этом примере user содержит данные,
загруженные асинхронным loader для маршрута, связанного с
компонентом UserProfile. Важно помнить, что
useAsyncValue автоматически блокирует рендер до завершения
загрузки данных, поэтому компонент получает готовый объект без
необходимости проверять состояние загрузки.
Особенности:
useAsyncValue работает только внутри компонентов,
вложенных в маршруты, где определен loader.useAsyncValue не возвращает значение — вместо этого ошибка
передается в систему обработки через
useAsyncError или родительский
ErrorBoundary.useAsyncError предназначен для
получения ошибок, возникших при выполнении асинхронного загрузчика
маршрута. Этот хук особенно полезен при создании кастомных компонентов
ошибок, которые должны обрабатывать разные типы ошибок на уровне
маршрута.
Пример использования:
import { useAsyncError } from "react-router-dom";
function UserErrorBoundary() {
const error = useAsyncError();
return (
<div>
<h2>Ошибка загрузки данных пользователя</h2>
<p>{error.message}</p>
</div>
);
}
В этом примере, если асинхронный loader маршрута
вызывает исключение, компонент UserErrorBoundary сможет
отобразить сообщение об ошибке. Это позволяет изолировать ошибки по
маршрутам и предотвращает падение всего приложения из-за одной неудачной
загрузки данных.
Особенности:
loader
или action, способный выбрасывать ошибки.ErrorBoundary для обработки ошибок на уровне целых веток
маршрутов.loader)Для полноценного использования этих хуков необходимо правильно
настроить асинхронные загрузчики маршрутов. loader — это
функция, которая выполняется перед рендерингом компонента маршрута и
возвращает промис с данными или выбрасывает ошибку.
Пример loader для маршрута пользователя:
async function userLoader({ params }) {
const response = await fetch(`/api/users/${params.userId}`);
if (!response.ok) {
throw new Error("Не удалось загрузить данные пользователя");
}
return response.json();
}
Здесь userLoader возвращает промис, который разрешается
в объект пользователя. Если запрос неудачен, выбрасывается ошибка,
которая затем обрабатывается через useAsyncError.
Маршрут с loader и компонентами:
import { createBrowserRouter, RouterProvider } from "react-router-dom";
const router = createBrowserRouter([
{
path: "/users/:userId",
element: <UserProfile />,
loader: userLoader,
errorElement: <UserErrorBoundary />,
},
]);
export default function App() {
return <RouterProvider router={router} />;
}
В этом примере маршруты полностью используют асинхронные хуки:
useAsyncValue получает данные из
userLoader.useAsyncError используется в
UserErrorBoundary для обработки ошибок загрузки.useAsyncError для создания специфичных для маршрута
сообщений об ошибках.loader и свои хуки useAsyncValue и
useAsyncError, что позволяет строить сложные приложения с
изолированной загрузкой данных.loader, чтобы
useAsyncValue сразу возвращал корректный тип.Эта система хуков позволяет React Router создавать чистый и предсказуемый поток асинхронных данных и ошибок, интегрируя их непосредственно с маршрутизацией без необходимости вручную управлять состоянием загрузки или ошибками. Она идеально подходит для современных приложений с большим количеством асинхронных зависимостей.