routeLoader$()
Route Loaders allow data to flow from the server to the Qwik Components. For this reason, Qwik routeLoaders should be always understood in the context of loading data in the server that is later consumed by a Qwik Component, if you want to create a RESTful endpoint, please check the endpoints guide instead.
They behave like RPC server-side functions that can be invoked by Qwik Components during rendering.
Declaring a loader
Route Loaders can only be declared inside the src/routes
folder, in a layout.tsx
or index.tsx
file, and they MUST be exported.
// src/routes/layout.tsx
import { routeLoader$ } from '@builder.io/qwik-city';
export const getProductData = routeLoader$(async () => {
// Add your data fetching code here (fetch, DB, Firebase, etc.)
// const res = await fetch('https://.../product')
// const products = await res.json()
// return products;
// We are returning sample data for this example
return {
product: {
name: 'Qwik City',
price: 100,
},
};
});
routeLoader$
s are not endpoints, it's an internal communication channel between the server and the Qwik Components. Also,routeLoader$
s must return a JSON serializable value.
routeLoader$
Using a routeLoader$
s can be used by any component in the application, as long as the loader is declared in a layout.tsx
or index.tsx
file that is part of the existing route.
// src/routes/index.tsx
import { routeLoader$ } from '@builder.io/qwik-city';
import { component$ } from '@builder.io/qwik';
export const useGetServerTime = routeLoader$(async () => {
return {
time: Date.now(),
}
});
export default component$(() => {
// Retrieve a reactive signal of the loader data
const signal = useGetServerTime(); // Signal<{time: number}>
return (
<div>
Server time: {signal.value.time}
</div>
);
});
It may appear that
useGetServerTime()
initiates the retrieval of the server data when the component renders. But in reality, therouteLoader$
associated withuseGetServerTime
gets executed eagerly at HTTP request. In this way, the asynchronous work of fetching server data can initiate as early as possible. (routeLoader$
function invokes eagerly on HTTP request regardless of whetheruseGetServerTime()
is invoked in the component.) For this reason, they are only allowed in thesrc/routes
folder, in alayout.tsx
orindex.tsx
files.
routeLoader$
s
Multiple Multiple routeLoader$
s are allowed across the whole application, and they can be used in any Qwik Component. You can even declare multiple routeLoader$
s in the same file.
File: src/routes/layout.tsx
import { component$ } from '@builder.io/qwik';
import { routeLoader$ } from '@builder.io/qwik-city';
import { Footer } from '../components/footer.tsx';
export const useGetServerTime = routeLoader$(async () => {
return {
time: Date.now(),
}
});
export default component$(() => {
const signal = useGetServerTime();
return (
<main>
<Slot />
<Footer />
</main>
);
});
File: src/components/footer.tsx
import { component$ } from '@builder.io/qwik';
// Import the loader from the layout
import { useGetServerTime } from '../routes/layout.tsx';
export const Footer = component$(() => {
// Consume the loader data
const signal = useGetServerTime();
return <footer>Server time: {signal.value.time}</footer>;
});
The above example shows using useGetServerTime()
in two different components across different files. This is intentional behavior.
File: src/routes/admin/index.tsx
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>
);
});
The above example shows two routeLoader$
s being used in the same file. A generic useLoginStatus
loader is used to check if the user is logged in, and a more specific useCurrentUser
loader is used to retrieve the user data.
routeLoader context
Just like request handlers such as onRequest
and onGet
, routeLoader$
s have access to the RequestEvent
object which includes information about the current request.
This information comes in handy when the loader needs to conditionally return data based on the request, or it needs to override the response status, headers or body manually.
import { routeLoader$ } from '@builder.io/qwik-city';
export const useServerTime = routeLoader$(
async ({headers, cookie, url, method, params}) => {
console.log('Request headers:', headers);
console.log('Request cookies:', cookie);
console.log('Request url:', url);
console.log('Request method:', method);
console.log('Request params:', params);
return {
time: Date.now();
}
}
);
When to use a routeLoader?
A routeLoader should be used when you need to provide some server-side data to your Qwik Components. For example, if you need to fetch some data from a database or an API, you can use a routeLoader to do that.
You should not use a routeLoader to create a REST API, for that you’d be better off using an Endpoint, which allows you to have tight control over the response headers and body.