[Vuejs]-Vue router isLoading show loader div in App.vue

2👍

so thanks to Neha Soni’s answer, I found out about

Pinia

and what I had in mind, looks like the following:

I installed pinia, created a store folder under src, and created there an isloading.ts file, which looks like this:

import { defineStore } from "pinia";
import { reactive, ref } from "vue";

export const  useLoaderState = defineStore("isLoading", () => {
    
    const state = ref(false)

const changeStateTrue = () => {
    state.value = true
}

const changeStateFalse = () => {
    state.value = false
}

    return { state, changeStateTrue, changeStateFalse }
})

In router/index.ts, I have the following logic that awaits for a bit before actually rendering the clicked route, and saves to the global variable isLoading as state a boolean:

router.beforeEach((to, from, next) => {
  const isLoading = useLoaderState();
  const { changeStateTrue } = isLoading;
  
  console.log("beforeach");
  changeStateTrue();
  console.log(isLoading.state);

  setTimeout(() => {
    next();
  }, 500);
});
router.afterEach((to, from) => {
  const isLoading = useLoaderState();
  const { changeStateFalse } = isLoading;

  console.log("aftereach");
  changeStateFalse();
  console.log(isLoading.state);
});

Finally, in my App.vue I have the following for my PreLoader, which is just for a loading screen:

 <script setup lang="ts">
   import { useLoaderState } from "./store/isloading";

   const isLoading = useLoaderState();
  </script>

  <template>
          <PreLoader v-if="isLoading.state" :class="[currentTheme]" />
  </template>

I wanted even my loader to change according to the already applied dark/light mode, so thats what the :class="[currentTheme]" is there for, what is important is the v-if="isLoading.state" , which first gets into this component with calling the Pinia way the isLoading global variable with

  • importing the defined store with import { useLoaderState } from "./store/isloading";
  • creating a constant in this current App.vue with the const isLoading = useLoaderState();

From there, the constant’s values and states (including the boolean which I wanted) lives reactively in this current component (in this case, the App.vue), and the v-if will get updated therefore dynamically.

👤Larry

1👍

The following two approaches can help you-

1. Using event bus-

  • Emit an event on the router’s before and after hook and pass a status true/false.
router.beforeEach((to, from, next) =>{
  eventbus.emit('loader-status', true)
});
router.afterEach((to, from) => {
  eventbus.emit('loader-status', true)
});
  • Listen to this event in your loader component and show/hide the loader as per the status passed by the event.
eventbus.on('loader-status', status => { this.showLoader = status })

Here you can read- How to use event buses in vue3.

2. Using Vuex-

  • Create a variable named showLoader in the Vuex state.
  • Update that variable on routers before and after the hook.
router.beforeEach((to, from, next) =>{
  // call a mutation to update the showLoader to true
});
router.afterEach((to, from) => {
  // call a mutation to update the showLoader to false
});
  1. Use this global variable’s value in the Loader component to show/hide the loader.
<Loader v-if="store.state.showLoader"></Loader>

Here you can read- How to set up Vuex in vue3.

NOTE-
I only provided the logical code, syntax would be different when you use any of the above approaches.

Leave a comment