В React Router (v6 и выше) загрузка данных с помощью
loader стала стандартным способом асинхронного получения
информации до отображения маршрута. Основной проблемой при использовании
loader в крупных приложениях является избыточная загрузка
данных и потенциальное замедление рендера. Для оптимизации важно
применять подходы, уменьшающие объём передаваемых данных и ускоряющие
рендеринг компонентов.
При работе с API часто запрашиваются объёмные объекты. Вместо того чтобы загружать весь ресурс, имеет смысл выбирать только нужные поля. Например:
export async function loader({ params }) {
const response = await fetch(`/api/users/${params.userId}?fields=id,name,email`);
if (!response.ok) {
throw new Response("Failed to load user", { status: response.status });
}
return response.json();
}
Ключевые моменты:
fields позволяет ограничить объём данных.Если маршрут содержит подкомпоненты с собственными loader-ами, имеет смысл выполнять lazy-загрузку для отдельных частей страницы:
export const routeConfig = {
path: "/dashboard",
element: <Dashboard />,
loader: async () => {
return fetch("/api/dashboard-summary").then(res => res.json());
},
children: [
{
path: "stats",
element: <Stats />,
loader: async () => fetch("/api/dashboard-stats").then(res => res.json())
}
]
};
Особенности подхода:
defer для частичной загрузки данныхReact Router поддерживает defer, позволяющий возвращать
часть данных сразу, а остальную асинхронно:
import { defer } from "react-router-dom";
export function loader() {
return defer({
user: fetch("/api/user/123").then(res => res.json()),
notifications: fetch("/api/notifications").then(res => res.json())
});
}
Принцип работы:
user сразу после
рендеринга, а уведомления подгружаются асинхронно.Suspense для отображения
placeholders до полной загрузки.Для уменьшения количества сетевых запросов имеет смысл кэшировать результаты loader:
const cache = new Map();
export async function loader({ params }) {
if (cache.has(params.userId)) {
return cache.get(params.userId);
}
const response = await fetch(`/api/users/${params.userId}`);
const data = await response.json();
cache.set(params.userId, data);
return data;
}
Преимущества:
Если ресурс большой, можно загружать данные частями:
export async function loader({ request }) {
const url = new URL(request.url);
const page = url.searchParams.get("page") || 1;
return fetch(`/api/posts?page=${page}&limit=20`).then(res => res.json());
}
Эффект:
Для уменьшения размера данных loader в React Router важно сочетать:
defer для частичной
асинхронной загрузки.Эти методы позволяют создавать быстрые, отзывчивые интерфейсы даже при большом объёме данных и сложной маршрутизации.