Watch our biggest AI launch event

Announcing Visual Copilot - Figma to production in half the time

Builder.io logo
Contact Sales
Platform
Developers
Contact Sales

Blog

Home

Resources

Blog

Forum

Github

Login

Signup

×

Visual CMS

Drag-and-drop visual editor and headless CMS for any tech stack

Theme Studio for Shopify

Build and optimize your Shopify-hosted storefront, no coding required

Resources

Blog

Get StartedLogin

‹ Back to blog

Web Development

Boost Your Site Perf with Qwik's useVisibleTask$ Hook

May 9, 2023

Written By Steve Sewell

Let me show you a technique you can use with the Qwik framework to have incredible stunning animated pages like this, while having a perfect performance score, even on mobile devices.

The trick, in a nutshell, is to never execute JavaScript until you absolutely need it.

As I scroll through the page below, the Network tab shows that JavaScript is streaming in only a bit at a time, executing only as needed.

The JavaScript that's sent is extremely minimal — bite-size amounts of code generated by the Qwik compiler only to run when needed.

Using visible tasks in Qwik

With Qwik, this takes no extra work. All we need is this useVisibleTask$ hook.

import { component$, useSignal, useVisibleTask$ } from "@builder.io/qwik";

export const Animated = component$(() => {
  const animate = useSignal(false);

  useVisibleTask$(() => {
    animate.value = true;
  });

  return (
    <div
      class={{
        animate: animate.value,
      }}
    >
      {/* Animated Stuff */}
    </div>
  );
});

As you may be able to tell from the code above, it is similar in some ways to the useEffect hook in React, except:

  1. It only runs when a component is visible
  2. This component never hydrates
  3. The component gets compiled down to its bare minimum pieces

Let’s break those down a little further, in reverse order:

Rather than your entire component downloading and executing on visible, which would simply be hydration on visible (aka progressive hydration), Qwik takes things further and just extracts the bare minimum logic needed.

So our component above simply compiles to these below 5 lines of code:

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

export const app_component_useVisibleTask_wbBu0Yp42Vw = () => {
    const [animate] = useLexicalScope();
    animate.value = true;
};

This is the absolute bare minimum code that needs to run in the client for this component. 

Even if our component had a massive DOM tree and a ton of initialization logic, it wouldn't matter — the above is all you need in the browser so that’s all you get.

For instance, your component could instead be something like this:

import { component$, useSignal, useVisibleTask$ } from "@builder.io/qwik";
import doReallyExpensiveWork from './huge-file'
import { SomeHugeComponent, LotsMoreComponents } from './huge-components'

export const Animated = component$(() => {
  const animate = useSignal(false);

  useVisibleTask$(() => {
    animate.value = true;
  });

  // NBD, this will only run on server
  const value = doReallyExpensiveWork()

  return (
    <div
      class={{
        animate: animate.value,
      }}
    >
      {/* NBD, these won't load in the browser, even tho this component does */}
      <SomeHugeComponent value={value} />
      <LotsMoreComponents />
    </div>
  );
});

But that’s ok. Even with all that extra work to do, the amount of code needed in the browser is the same, so that tiny snippet of code above is still all we would send to the browser.

Importantly, our component will deliver as pure HTML. This is all the browser gets:

  <div
    on:qvisible="app_component_usevisibletask_wbbu0yp42vw.js"
  >
    <!-- Animated stuff! -->
  </div>

Unlike today's frameworks, no JavaScript specific to this component will run on startup of your page. This is how we achieve such great performance scores — there is no better way to be fast than to do no work at all.

So with that tiny HTML, and the Qwikloader (a tiny <1kb JS file that listens to events and loads files), we can prefetch that tiny JS in advance and be ready to execute it only when needed.

Once our page loads, our Qwikloader will find that JS URL in the DOM and prefetch it. 

Then, once this element is visible, we will execute the bare minimum code we showed previously:

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

export const app_component_useVisibleTask_wbBu0Yp42Vw = () => {
    const [animate] = useLexicalScope();
    animate.value = true;
};

Because this code simply changes a signal, and Qwik can listen to signal changes and granularly update the DOM directly (no vdom involved), our UI is now updated with its beautiful animations.

Now keep in mind we are showing a simple example here, but think of how this scales. No matter how complex your site gets, the goal here is to load and execute as little as possible, as late as possible.

This is in contrast to standard hydration, that must download and execute the whole world (all code for all components on your page) right on startup, wether or not you even need any of it, just to create the initial state tree, bindings, and event listeners.

Luckily, we don’t need any of this with Qwik, due to the painstaking work we did on the framework to create a whole new model for all of this, which we call Resumability.

Our goal with Qwik is to make it as effortless as possible to build incredible applications. 

They should be easy, they should run fast, and that should require no extra work from you.

If you haven’t already, go check out reflect.app for yourself, or any other site in the Qwik showcase.

Or, if you would like to try out Qwik for yourself, you can get started in just one command:

npm create qwik@latest

Introducing Visual Copilot: convert Figma designs to high quality code in a single click.

Try Visual Copilot

Share

Twitter
LinkedIn
Facebook
Hand written text that says "A drag and drop headless CMS?"

Introducing Visual Copilot:

A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot
Newsletter

Like our content?

Join Our Newsletter

Continue Reading
AI5 MIN
Introducing Visual Copilot 2.0: Design to Interactive
October 31, 2024
Design Systems8 MIN
Design Systems Explained
October 18, 2024
Visual Editing7 MIN
Visual editing is bridging the gap between developers and designers
October 11, 2024