A simple useLoading composable for your Vue 3 projects

A simple useLoading composable for your Vue 3 projects

ยท

2 min read

Hey guys,

Wanna share with you all a simple Vue composable function that lies in every Vue project of mine ๐Ÿ˜Ž.

Please meet the useLoading ๐Ÿš€ A simple reusable composable that handles loading state flawlessly for you โค๏ธ.

Before "useLoading", before composable

I (and most of us) have been using this kind of approach before composable ๐Ÿคฃ

const isLoading = ref(false);

const loadUsers = async () => {
    isLoading.value = true;

    const res = await getUsers().catch(() => undefined)); // catch to avoid throw

    isLoading.value = false;

    users.value = res?.users ?? [];
};

onMounted(loadUsers);

So before when composable wasn't a thing, we likely had to copy/paste to every component that needed the isLoading indicator.

Vue's useLoading composable

With the composable introduced in Vue 3. It allows us to create multiple reusable pieces.

So I created this for my projects this bad boy. useLoading composable is a global one and can be reused everywhere.

// src/composables/useLoading.ts

import { ref } from 'vue';

export const useLoading = (initializedState = false) => {
  const isLoading = ref(initializedState);

  const startLoading = () => {
    isLoading.value = true;
  };

  const stopLoading = () => {
    isLoading.value = false;
  };

  const withLoading = (handler: () => Promise<void>) => async () => {
    if (isLoading.value) {
      return;
    }

    startLoading();

    await handler().catch((err) => console.error(err));

    stopLoading();
  };

  return {
    isLoading,
    startLoading,
    stopLoading,
    withLoading,
  };
};

Default usage

By default, you can manually trigger startLoading and stopLoading, then use isLoading to check the state.

const { isLoading, startLoading, stopLoading } = useLoading();

startLoading();
// do something so long here
stopLoading();

HoF: withLoading

The awesomeness comes from this bad boy ๐Ÿ˜Ž. Having a high-order function to wrap our logic/handlers there and it's automatically triggered startLoading on start and stopLoading on finished.

const { isLoading, withLoading } = useLoading();

const loadUsers = withLoading(async () => {
    const res = await getUsers().catch(() => undefined));
    users.value = res.users ?? [];
});

onMounted(loadUsers);

Not to mention, the withLoading will not trigger another call if isLoading === true , thus ensuring we don't dispatch a lot of API calls/handlers/etc by mistake ๐Ÿ›ก๏ธ.

Moving forward

Not only useLoading, but also there are several cases which you could create as a composable and reuse:

  • useError (error from API, error from FE, etc)

  • useValidation (simple frontend validation)

  • useRouteParams (return the Vue's router params in strict types)

  • useRouteSearchParams (same as above but for URL Search Params aka GET params)

  • and many more...

Closing topic

And that's that, I hope you will like the useLoading composable. I really like the HoF withLoading above.

Thanks for reading!

ย