Routing - Qwik for Angular Developers

In this article we will look at how routing works in Qwik applications. We will look at how to define routes, how to navigate between routes and how to access route parameters and use route loaders. It does not cover Qwik's layout functionality and the route endpoints.

Qwik is separated into two parts, the Qwik core framework and Qwik City, which is a collection of additional functionality that is useful for building applications. Qwik City contains the routing. Let's assume you have already a Qwik app up and running.

Route definition

Hey Angular dev! How are you writing your route definitions? I bet you are using the RouterModule and pass an array of routes to the forRoot or forChild method. That's at least the most typical way for routing in Angular applications. In Qwik we are using the filesystem to define the routes. That's right, no routes array to configure here. Instead we are using the filesystem to define the routes. Let's look at an example. The routes are all defined in the routes folder.

/src
  /routes
    /home
      index.tsx
    /about
      index.mdx
    /contact
      index.tsx

The index.tsx and index.mdx files are both route endpoints. The index.mdx file is an extended markdown file, which is able to render components inside the markdown. This is also a feature of Qwik City. The index.tsx file is a regular Qwik component. Routes must be named index plus file extension. You can not define /src/routes/about.tsx for example.

Route paramters

In Angular you would define your routes in the following way:

const routes: Routes = [{ path: 'user/:id', component: UserComponent }];

Here we are defining a route with a parameter called id. Inside of the UserComponent you can access the the id parameter by injecting the ActivatedRoute and access either the current route snapshot or listening to the params stream. The Qwik way of defining a route with a parameter is to use a folder with the parameter name. With square brackets around the parameter name you can indicate that this path segment is a parameter.

/src/routes/user/[id]/index.tsx

Inside of your component you can now access the parameter by using the useLocation hook as follows

import { component$ } from '@builder.io/qwik';
import { useLocation } from '@builder.io/qwik-city';

export default component$(() => {
  const location = useLocation();

  return <>User id: {location.params.id}</>;
});

Route loaders

This is probably the most interesting part of the routing topic and differs from Angular. Maybe similar functionality is available in Angular Universal, but honestly I don't know.

The two most common ways of loading route specific data is to either use a route resolver or to trigger an API request via a service based on the route parameter. The service usually triggers an HTTP request to the server.

Qwik provides so called route loaders to load data for a route. A route loader is a function that is called when a route is loaded inside the component. The difference to a route resolver is that this route loader is executed on the server. Qwik's documentation says

[...] Qwik routeLoaders should be always understood in the context of loading data in the server that is later consumed by a Qwik Component [...]

Let's have a look. Inside of the components index.tsx file you can create an exported function using the routeLoader$. The function can be async and can return any JSON serializable data.

import { routeLoader$ } from '@builder.io/qwik-city';

export const useUsersData = routeLoader$(async () => {
  // Here you can access the database or trigger API requests, etc.
  // You can also access the file system using Node APIs. Keep in mind that
  // some hosting providers do not support Node APIs, especially on the so called "edge".

  return [
    { id: 1, name: 'Hans Wurst' },
    { id: 2, name: 'Klaus Kleber' },
  ];
});

Now we can use this route loader inside of our component. Imagine that we have created a new hook using our defined route loader.

import { component$ } from '@builder.io/qwik';

// Previously defined route loader

export default component$(() => {
  const users = useUsersData();

  return (
    <>
      <h1>Users</h1>
      <ul>
        {users.value.map((user) => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
    </>
  );
});

The loader function returns a signal, which is an asynchronous value. Access the signal's value using the value property.

Takeaways

  • Qwik uses the filesystem to define routes
  • Qwik uses route loaders to load data for a route
  • Route loaders are called inside the component and executed on the server. They are no HTTP endpoints. They are a Qwik internal communication channel of loading data for a route.
  • Route parameters are defined using a folder with square brackets around the parameter name

If you have any questions feel free to drop me a message on LinkedIn or Twitter.

Have an awesome day!

Resources