React Router предоставляет возможность управления данными на уровне
маршрутов через функции loader и action. Эти
функции используются для асинхронной загрузки данных и обработки
действий пользователей (например, отправки форм). Понимание их работы и
отладка являются ключевыми при разработке сложных приложений.
loaderФункция loader вызывается каждый раз, когда маршрут
активируется. Она может возвращать данные синхронно или через
Promise. Основные моменты:
useLoaderData.loader
асинхронный. Необходимо использовать async/await и
обрабатывать возможные ошибки.params), объект запроса
(request) и данные родительского маршрута
(context).Пример структуры loader:
export async function loader({ params, request }) {
try {
const response = await fetch(`/api/items/${params.id}`);
if (!response.ok) throw new Error('Ошибка загрузки данных');
return await response.json();
} catch (error) {
throw new Response("Ошибка сервера", { status: 500 });
}
}
Ключевой момент: если функция выбрасывает исключение, React Router
автоматически перенаправляет к ErrorBoundary для данного
маршрута.
actionaction обрабатывает данные, отправленные пользователем,
обычно через формы. Основные принципы:
redirect().async/await.params для
параметров маршрута, объект request с информацией о запросе
и телом формы.Пример структуры action:
import { redirect } from "react-router-dom";
export async function action({ request, params }) {
const formData = await request.formData();
const title = formData.get("title");
try {
const response = await fetch(`/api/items/${params.id}`, {
method: "POST",
body: JSON.stringify({ title }),
headers: { "Content-Type": "application/json" },
});
if (!response.ok) throw new Error("Ошибка обновления");
return redirect(`/items/${params.id}`);
} catch (error) {
return { error: error.message };
}
}
Важно: action может возвращать данные для формы или
перенаправление, что позволяет контролировать пользовательский
поток.
loader и
actionДля эффективной отладки необходимо учитывать несколько техник:
export async function loader({ params, request }) {
console.log("Params:", params);
console.log("Request URL:", request.url);
try {
const data = await fetchData(params.id);
console.log("Loaded data:", data);
return data;
} catch (err) {
console.error("Loader error:", err);
throw err;
}
}
Аналогично для action:
export async function action({ request, params }) {
console.log("Action params:", params);
const formData = await request.formData();
console.log("Form data:", Object.fromEntries(formData));
try {
const result = await performAction(formData);
console.log("Action result:", result);
return result;
} catch (err) {
console.error("Action error:", err);
throw err;
}
}
catch и
ErrorBoundaryReact Router позволяет перехватывать ошибки loader и
action через маршруты с errorElement. Это
особенно полезно для комплексных форм:
<Route
path="items/:id"
loader={loader}
action={action}
element={<ItemDetail />}
errorElement={<ErrorDisplay />}
/>
throw new Response(...)) для проверки
поведения маршрутов.Для сложных операций полезно вынести бизнес-логику из
loader и action в отдельные функции. Это
упрощает тестирование и отладку:
async function fetchItem(id) {
const response = await fetch(`/api/items/${id}`);
if (!response.ok) throw new Error("Ошибка загрузки");
return response.json();
}
export async function loader({ params }) {
return fetchItem(params.id);
}
useLoaderData() позволяет получать данные из
loader напрямую.useActionData() используется для обработки
результатов action.useNavigation() показывает текущий статус перехода или
сабмита формы, что удобно при отладке асинхронных операций.loaderПричина: запрос не дожидается асинхронного результата или не
возвращается объект. Решение: всегда использовать await и
возвращать результат.
actionПричина: форма должна использовать method="post" и
находиться внутри <Form> из
react-router-dom. Проверка:
<Form method="post">.
Если loader или action выбрасывают
исключение, но нет errorElement, React Router отобразит
пустую страницу. Решение: добавить errorElement на
маршрут.
Причина: нужно использовать useNavigation() или
useSubmit() для контроля состояния, либо перенаправление
через redirect() после успешного действия.
errorElement для визуальной диагностики
ошибок.useActionData() с визуальными
индикаторами загрузки и ошибок.Эти подходы позволяют не только выявлять ошибки в loader
и action, но и обеспечивать предсказуемое поведение
приложения при асинхронной загрузке данных и обработке форм.