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

7. Обработка ошибок

Remix предоставляет отличную систему обработки ошибок. Каждый маршрут может иметь свой ErrorBoundary, который перехватывает ошибки из loader, action и компонента.

import { useRouteError, isRouteErrorResponse } from "@remix-run/react";
export function ErrorBoundary() {
const error = useRouteError();
// Ошибки, брошенные как Response (throw new Response(...))
if (isRouteErrorResponse(error)) {
return (
<div>
<h1>{error.status} {error.statusText}</h1>
<p>{error.data}</p>
</div>
);
}
// Обычные JavaScript ошибки
if (error instanceof Error) {
return (
<div>
<h1>Что-то пошло не так</h1>
<p>{error.message}</p>
</div>
);
}
return <h1>Неизвестная ошибка</h1>;
}
export async function loader({ params }) {
const user = await getUser(params.id);
if (!user) {
throw new Response("Пользователь не найден", {
status: 404,
statusText: "Not Found",
});
}
return json(user);
}
export async function loader() {
try {
return json(await fetchData());
} catch (err) {
// Remix перехватит это в ErrorBoundary
throw new Error("Ошибка загрузки данных");
}
}
export async function action({ request }) {
const data = await request.formData();
const result = await riskyOperation(data.get("id"));
if (!result.ok) {
// Возвращаем данные об ошибке (не бросаем)
return json({ error: result.message }, { status: 400 });
}
return redirect("/success");
}

Ключевое преимущество Remix — ошибки изолируются в своём маршруте:

app/routes/
dashboard.tsx ErrorBoundary здесь...
dashboard.users.tsx ...перехватит ошибку здесь
dashboard.stats.tsx ...или здесь

Если dashboard/stats бросает ошибку, ErrorBoundary в dashboard/stats.tsx показывает ошибку только в области статистики, остальная часть dashboard продолжает работать!

В root.tsx обязательно нужен ErrorBoundary как страховка:

root.tsx
export function ErrorBoundary() {
const error = useRouteError();
return (
<html>
<head><title>Ошибка</title></head>
<body>
<div className="error-page">
<h1>Критическая ошибка</h1>
{isRouteErrorResponse(error)
? `${error.status}: ${error.statusText}`
: "Что-то пошло не так"}
</div>
</body>
</html>
);
}
import { data } from "@remix-run/node";
export async function loader({ params }) {
const post = await getPost(params.slug);
if (!post) {
throw data("Пост не найден", { status: 404 });
}
return { post };
}