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) => {
// This code runs only on the server, after every navigation
const res = await fetch(`https://.../products/${requestEvent.params.productId}`);
const product = await res.json();
return product as Product;
});
export default component$(() => {
// In order to access the `routeLoader$` data within a Qwik Component, you need to call the hook.
const signal = useProductDetails(); // Readonly<Signal<Product>>
return <p>Product name: {signal.value.product.name}</p>;
});
ルートローダーは、データベースまたは API からデータを取得するのに最適です。たとえば、CMS、天気 API、またはデータベースからのユーザーリストからデータを取得するために使用できます。
REST API を作成するために
routeLoader$
を使用しないでください。その場合は、レスポンスヘッダーと本文を厳密に制御できる エンドポイント を使用することをお勧めします。
routeLoader$
複数の アプリケーション全体で複数の routeLoader$
を使用でき、任意の Qwik コンポーネントで使用できます。**同じファイルに複数の routeLoader$
を宣言することもできます**。
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 the loader from the layout
import { useProductData } from '../routes/layout.tsx';
export const Footer = component$(() => {
// Consume the loader data
const signal = useProductData();
return <footer>Product name: {signal.value.product.name}</footer>;
});
上記の例は、異なるファイルの 2 つの異なるコンポーネントで 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>Admin</h1>
{loginStatus.value.isUserLoggedIn ? (
<p>Welcome {currentUser.value.user.name}</p>
) : (
<p>You are not logged in</p>
)}
</section>
);
});
上記の例は、同じファイルで 2 つの routeLoader$
を使用する方法を示しています。ユーザーがログインしているかどうかを確認するための汎用的な useLoginStatus
ローダーと、ユーザーデータを取得するためのより具体的な useCurrentUser
ローダーが使用されています。
RequestEvent
ミドルウェア や エンドポイント の onRequest
および onGet
と同様に、routeLoader$
は RequestEvent
API にアクセスできます。これには、現在の 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);
// Use request details to fetch personalized data
const res = fetch(`https://.../recommendations?user=${requestEvent.params.user}`);
const recommendedProducts = (await res.json()) as Product[];
return recommendedProducts;
});
routeLoader$
内で routeLoader$
データにアクセスする
別の requestEvent.resolveValue
メソッドを使用して、1 つの routeLoader$
のデータに別の routeLoader$
の内部からアクセスできます。
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) => {
// Resolve the product details from the other loader
const product = await requestEvent.resolveValue(useProductDetails);
// Use the product details to fetch personalized data
const res = fetch(`https://.../recommendations?product=${product.id}`);
const recommendedProducts = (await res.json()) as Product[];
return recommendedProducts;
});
同じ API を使用して、
routeAction$
またはglobalAction$
のデータにアクセスすることもできます。
routeLoader$
での失敗値
routeLoader$
は、fail
メソッドを使用して失敗値を返すことができます。これは、ローダーが期待されるデータの読み込みに成功しなかったことを示す特殊な値です。
さらに、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 a failed value to indicate that product was not found
return requestEvent.fail(404, {
errorMessage: 'Product not found'
});
}
return {
productName: product.name
};
});
export default component$(() => {
const product = useProductDetails();
if (product.value.errorMessage) {
// Render UI for failed value
return <div>{product.value.errorMessage}</div>;
}
return <div>Product name: {product.value.productName}</div>;
});
ローダーでの相対 URL の処理
サーバー側の実行環境では、適切な機能のために相対 URL を絶対 URL に変換することが重要です。これは、useLocation()
関数の origin
を相対 URL のプレフィックスにすることで実現できます。
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>Relative URL: {relativeUrl}</div>
<div>Absolute URL: {absoluteUrl}</div>
</section>
);
});
パフォーマンスに関する考慮事項
ルートローダーは、サーバー上で、すべてのナビゲーション後に実行されます。これは、ユーザーが SPA または MPA でページに移動するたびに実行され、ユーザーが同じページに移動する場合でも実行されることを意味します。
ローダーは、Qwikミドルウェアハンドラー(onRequest
、onGet
、onPost
など)の後、Qwikコンポーネントのレンダリング前に実行されます。これにより、ローダーはできるだけ早くデータのフェッチを開始でき、レイテンシを削減できます。