Skip to content

8

Optimizing Data Fetching

In the previous chapter, you fetched data for the Dashboard page. However the data requests are creating an unintentional waterfall.

In this chapter...

Here are the topics we will cover:

How to reduce data fetching time by passing requests in parallel

How to trigger data requests only when necessary

Simulate a slow data fetch to see what happens.

Parallel Data Fetching

With routeLoader$ the page is render blocking until all the data is fetched. It is important to reduce the data fetching time. To do this, we can fetch data in parallel.

For the moment with sequential data fetching, in your application, the useFetchData() request time is 1.23s. We can reduce this time by fetching data in parallel. 👇

Note: The request time may vary depending on your internet connection and your computer's speed.

Time taken to fetch data sequentially

Now let's move on to setting up parallel data loading.

To pass the requests in parallel, we have several choices:

  • Promise.all() - Combine multiple promises into a single promise.
  • Promise.allSettled() - Wait for all promises to be settled.
  • Using multiple routeLoader$ - One for each request.🤔

Multiple routeLoader$

Multiple routeLoader$ are allowed across the whole application, and they can be used in any Qwik Component. You can even declare multiple routeLoader$ in the same file.

Let's create three new routeLoader$ functions to fetch the data in parallel:

/src/routes/dashboard/layout.tsx

We have created three new routeLoader$ functions to fetch the data in parallel. Now let's update the src/routes/dashboard/index.tsx file to use these new routeLoaders.

/src/routes/dashboard/index.tsx

Now, with the new routeLoader$ functions, the data is fetched in parallel. This reduces the time taken to fetch the data.

Time taken to fetch data in parallel

The time taken to fetch the data in parallel is now 0.448s (The longest request time). This is a significant improvement over the previous 1.23s. 🚀

An advantage of using routeLoader$for each request, in addition to reducing the data fetching time, is to separate the data based on their usage. This is particularly useful if you need to use only certain data in a specific page or component.

Again, all of this will depend on your application and your needs.

For our dashboard, we need all the data for our page, so we will use only one routeLoader$ for all the data. To do this, we will use Promise.all() to combine the three requests into one.

It’s time to take a quiz!

Test your knowledge and see what you’ve just learned.

What is the advantage of using multiple routeLoader$?

You must choose response !

Promise.all()

/src/routes/dashboard/layout.tsx
/src/routes/dashboard/index.tsx

One request is now sent to fetch all the data. The loading time of this request is the same as the previous one, 0.45s.👇

Time taken to fetch data in parallel with Promise.all()

It’s time to take a quiz!

Test your knowledge and see what you’ve just learned.

What is the purpose of using Promise.all() in data fetching?

You must choose response !

Triggering Data Requests

We placed our routeLoader$ in the layout, this means the request is sent every time the route is loaded (and even before...). The problem here is that the request will be triggered when navigating to all dashboard tabs.

In the /src/routes/dashboard/layout.tsx file, add a console.log to see when the request is triggered.

/src/routes/dashboard/layout.tsx

Open the browser, when hovering over any dashboard tab, the request is triggered.👇

When our routeLoader$ is in layout, the data request is triggered when hovering over any dashboard tab.

This behavior would be appropriate if we needed this data for all the dashboard tabs.

As a reminder, in our application we only need this data for the dashboard home page. It would be better if the request is triggered only when the user navigates to the dashboard home page.

To trigger the routeLoader$ only when necessary, simply move it to our src/routes/dashboard/index.tsx file.

/src/routes/dashboard/layout.tsx
/src/routes/dashboard/index.tsx

Now, the request is only triggered when the user navigates to the dashboard home page.👇

When our routeLoader$ is in index, the data request is triggered only when navigating to the dashboard home page.

It’s time to take a quiz!

Test your knowledge and see what you’ve just learned.

What happens when routeLoader$ is placed in the layout?

You must choose response !

Congratulations 🙌, you have now optimized the data loading by passing them in parallel and triggering the requests only when necessary.🏆

Simulating Slow Data Fetch

Récuperer les données en parrallele est une bonne premiere étape, mais que se passet il si une requete est plus lente que les autres?

Let's simulate a slow data fetch to see what happens.👇

In the /src/lib/data.ts file, add a delay of 3 seconds to the fetchRevenue() function.

/src/lib/data.ts

Now open http://localhost:5173/dashboard/ in a new tab and notice how the page takes longer to load. In your terminal, you should also see the following messages:

Here, you've added an artificial 3-second delay to simulate a slow data fetch. The result is that now your whole page is blocked while the data is being fetched.

Which brings us to a common challenge developers have to solve:

With dynamic rendering, your application is only as fast as your slowest data fetch.

The soluce to this problem is Streaming

In the next chapter, you'll learn how to use streaming to optimize user's experience.

It’s time to take a quiz!

Test your knowledge and see what you’ve just learned.

What is the effect of simulating a slow data fetch?

You must choose response !

Source code

You can find the source code for chapter 8 on GitHub.

You've Completed Chapter 8

Nice! You've learned about optimizing data fetching in Qwik.

Next Up

9: Streaming

Learn how to improve your user's experience by adding streaming.