routeLoader$()
Загрузчики маршрутов загружают данные на сервер, чтобы они стали доступны для использования в компонентах Qwik. Они срабатывают, когда происходит навигация SPA/MPA, чтобы их могли вызывать компоненты Qwik во время рендера.
Загрузчики маршрута могут быть объявлены только внутри папки src/routes
, в файле layout.tsx
или index.tsx
, и они ДОЛЖНЫ быть экспортированы.
Если вы хотите управлять общими многократно используемыми routeLoaders$, необходимо, чтобы эта функция была реэкспортирована из файла 'layout.tsx' или 'index.tsx' существующего маршрута, иначе она не будет запущена или выбросит исключение. Для получения дополнительной информации обратитесь к разделу рецептов.
import { component$ } from '@builder.io/qwik';
import { routeLoader$ } from '@builder.io/qwik-city';
export const useProductDetails = routeLoader$(async (requestEvent) => {
// Этот код выполняется только на сервере, после каждой навигации
const res = await fetch(`https://.../products/${requestEvent.params.productId}`);
const product = await res.json();
return product as Product;
});
export default component$(() => {
// Чтобы получить доступ к данным `routeLoader$` в компоненте Qwik, необходимо вызвать хук.
const signal = useProductDetails(); // Readonly<Signal<Product>>
return <p>Наименование товара: {signal.value.product.name}</p>;
});
Загрузчики маршрутов идеально подходят для получения данных из базы данных или API. Например, вы можете использовать их для получения данных из CMS, API погоды или списка пользователей из вашей базы данных.
Вы не должны использовать
routeLoader$
для создания REST API, для этого лучше использовать Endpoint, который позволяет жёстко контролировать заголовки и тело ответа.
routeLoader$
-ов
Несколько В приложении разрешено использовать несколько routeLoader$
-ов, и их можно использовать в любом компоненте Qwik. Вы даже можете объявить несколько загрузчиков маршрута в одном файле.
import { component$ } from '@builder.io/qwik';
import { routeLoader$ } from '@builder.io/qwik-city';
import { Footer } from '../components/footer.tsx';
export const useProductData = routeLoader$(async () => {
const res = await fetch('https://.../product');
const product = await res.json() as Product;
return product;
});
export default component$(() => {
const signal = useProductData();
return (
<main>
<Slot />
<Footer />
</main>
);
});
import { component$ } from '@builder.io/qwik';
// Импорт загрузчика из макета
import { useProductData } from '../routes/layout.tsx';
export const Footer = component$(() => {
// Использование данных загрузчика
const signal = useProductData();
return <footer>Наименование товара: {signal.value.product.name}</footer>;
});
Приведённый выше пример показывает использование useProductData()
в двух разных компонентах и в разных файлах. Это намеренное поведение.
import { component$ } from '@builder.io/qwik';
import { routeLoader$ } from '@builder.io/qwik-city';
export const useLoginStatus = routeLoader$(async ({ cookie }) => {
return {
isUserLoggedIn: checkCookie(cookie),
};
});
export const useCurrentUser = routeLoader$(async ({ cookie }) => {
return {
user: currentUserFromCookie(cookie),
};
});
export default component$(() => {
const loginStatus = useLoginStatus();
const currentUser = useCurrentUser();
return (
<section>
<h1>Администратор</h1>
{loginStatus.value.isUserLoggedIn ? (
<p>Привет, {currentUser.value.user.name}</p>
) : (
<p>Вы не авторизованы</p>
)}
</section>
);
});
Приведённый выше пример показывает использование двух routeLoader$
-ов в одном файле. Общий загрузчик useLoginStatus
используется для проверки того, вошёл ли пользователь в систему, а более специфический загрузчик useCurrentUser
используется для получения данных пользователя.
RequestEvent
Подобно промежуточному ПО или конечной точке, onRequest
и onGet
, routeLoader$
имеет доступ к API RequestEvent
, который содержит информацию о текущем HTTP-запросе.
Эта информация пригодится, когда загрузчику нужно вернуть данные по условию на основе запроса, или ему нужно переопределить статус ответа, заголовки или тело.
import { routeLoader$ } from '@builder.io/qwik-city';
export const useProductRecommendations = routeLoader$(async (requestEvent) => {
console.log('Request headers:', requestEvent.request.headers);
console.log('Request cookies:', requestEvent.cookie);
console.log('Request url:', requestEvent.url);
console.log('Request method:', requestEvent.method);
console.log('Request params:', requestEvent.params);
// Используйте параметры запроса для получения персонализированных данных
const res = fetch(`https://.../recommendations?user=${requestEvent.params.user}`);
const recommendedProducts = (await res.json()) as Product[];
return recommendedProducts;
});
routeLoader$
из другого routeLoader$
.
Доступ к данным Вы можете получить доступ к данным одного routeLoader$
из другого routeLoader$
, используя метод requestEvent.resolveValue
.
import { routeLoader$ } from '@builder.io/qwik-city';
export const useProductDetails = routeLoader$(async (requestEvent) => {
const res = await fetch(`https://.../products/${requestEvent.params.productId}`);
const product = await res.json();
return product;
});
export const useProductRecommendations = routeLoader$(async (requestEvent) => {
// Получение информации о товаре из другого загрузчика.
const product = await requestEvent.resolveValue(useProductDetails);
// Используем полученные данные о товаре для получения персонализированных данных.
const res = fetch(`https://.../recommendations?product=${product.id}`);
const recommendedProducts = (await res.json()) as Product[];
return recommendedProducts;
});
Тот же API можно использовать для доступа к данным из
routeAction$
илиglobalAction$
.
routeLoader$
.
Неудачная загрузка данных с routeLoader$
может использовать метод fail
для возврата значения failed, которое является специальным значением, указывающим на то, что загрузчику не удалось загрузить ожидаемые данные.
Кроме того, функция fail
позволяет routeLoader$
переопределять код статуса HTTP, например, возвращать 404.
Это полезно, когда загрузчику нужно вернуть значение "ошибки", которое не является undefined
, но должно указывать на то, что данные не удалось загрузить.
import { component$ } from '@builder.io/qwik';
import { routeLoader$ } from '@builder.io/qwik-city';
export const useProductDetails = routeLoader$(async (requestEvent) => {
const product = await db.from('products').filter('id', 'eq', requestEvent.params.productId);
if (!product) {
// Возвращает значение, указывающее на то, что товар не был найден.
return requestEvent.fail(404, {
errorMessage: 'Товар не найден'
});
}
return {
productName: product.name
};
});
export default component$(() => {
const product = useProductDetails();
if (product.value.errorMessage) {
// Отображение неудачной загрузки данных.
return <div>{product.value.errorMessage}</div>;
}
return <div>Наименование товара: {product.value.productName}</div>;
});
Обработка относительных URL-адресов в загрузчиках
В среде выполнения на стороне сервера крайне важно преобразовать относительные URL-адреса в абсолютные URL-адреса для обеспечения надлежащей функциональности. Этого можно добиться, добавив к относительному URL-адресу префикс origin
из функции useLocation()
.
import { component$ } from '@builder.io/qwik';
import { useLocation } from '@builder.io/qwik-city';
export default component$(() => {
const location = useLocation();
const relativeUrl = '/mock-data';
const absoluteUrl = location.url.origin + relativeUrl;
return (
<section>
<div>Относительный URL: {relativeUrl}</div>
<div>Абсолютный URL: {absoluteUrl}</div>
</section>
);
});
Соображения по производительности
Загрузчики маршрутов выполняются на сервере после каждой навигации. Это означает, что они выполняются каждый раз, когда пользователь переходит на страницу в SPA или MPA, и выполняются, даже если пользователь переходит на ту же страницу.
Загрузчики выполняются после обработчиков маршрутов Qwik (onRequest
, onGet
, onPost
и т.д.), и перед рендером компонентов Qwik. Это позволяет загрузчикам начать получение данных как можно быстрее, уменьшая задержку.