skip to Main Content

I’m building a website and I’m fetching some data in some scroll components but I want a loading screen when someone opens the website till everything is done so they won’t load one by one (the page doesn’t look great with empty spaces and I don’t really want to use placeholders also showing multiple loading animations for each scroll component doesn’t look nice).

Like: Enter Website — Show a full page animation (like my logo in the middle of the page and a loading animation) — API loaded everything — enter Main Page.

It loads pretty fast the way I did it now but I’m not even sure if I should call initGetBooks() in onMounted or not (or if it’s a good practice the way I did it), when I did call in onMounted it was too slow for my like. I am a bit noob on this, I have some experience with react-native.

I am using this to fetch data atm:

// composables/useAPIFetch.ts

import axios from 'axios'

export const useAPIFetch = () => {
  const baseURL = 'http://localhost:2222'
 // const storeUser = useStoreUser()
  const token = 'sometoken'
  
  return axios.create({
    baseURL,
   // mode: 'no-cors',
    headers: {
      Authorization: `Bearer ${token}`,
    }
  })
}
// components/Latest.vue
--- ...
                <div data-slide-recent @scroll="initScroll()" class="flex items-stretch gap-5 overflow-hidden overflow-x-auto invisible-scroll">
                    <template v-for="book in books">
                        <div class="w-11/12 min-w-[91.666667%] xs:w-80 xs:min-w-[20rem] md:w-1/3 md:min-w-[33.333333%] lg:w-1/4 lg:min-w-[25%]">
                            <CardsRecentPod :key="book.id" :title="book.media.metadata.title ? `${book.media.metadata.title} - ${book.media.metadata.authorName}` : ''" :duration="secondsToHoursAndMinutes(book.media.duration)" :href="'http://localhost:3333/item/' + book.id" :cover-image="book.media.coverPath ? 'http://localhost:3333/api/items/' + book.id + '/cover?token=sometoken' : 'http://localhost:2222/placeholder_cover.jpg'" />
                        </div>
                    </template>
</div>
----- ...
<script lang="ts" setup >
const api = useAPIFetch(
const books = ref<any[]>([]);

async function initGetBooks(): Promise<void> {
    const { data: libInfo } = await api({
        method: 'post',
        url: '/api/authorize'
    })

    const { data: booksInfo } = await api({
        method: 'get',
        url: '/api/libraries/' + libInfo.userDefaultLibraryId + '/items?limit=8&sort=addedAt&desc=1'
    })
    books.value = booksInfo.results
}


let element: HTMLDivElement
if (typeof document !== "undefined") {
    element = document.querySelector("[data-slide-recent]") as HTMLDivElement
}
async function initScroll(this: any): Promise<void> {
    if (typeof element === "undefined" || element === null) {
        return
    }

    prevIsVisible.value = element.scrollLeft <= 0 ? false : true
    nextIsVisible.value = element.scrollLeft >= element.scrollWidth - element.offsetWidth - 1 ? false : true
}

function scrollToLeft(): void {
    if (typeof element === "undefined" || element === null) {
        return
    }
    element.scrollLeft -= element.clientWidth
}

function scrollToRight(): void {
    if (typeof element === "undefined" || element === null) {
        return
    }
    element.scrollLeft += element.clientWidth
}

await initGetBooks()

onMounted(() => {
    if (window !== null) {
        initScroll()
    }
})

</script>

Any advice is greatly appreciated.

I tried playing with NuxtLoadingIndicator and some stuff but no luck.

2

Answers


  1. Chosen as BEST ANSWER

    I changed some stuff but i have a problem and i cant find any fix for it. When im opening/reloading the page or i navigate seems to work just fine but when i make any changes in the code and it autoupdates in dev mode im getting this errors in the Chrome console and i dont think its a server problem, any idea what's going wrong here or what other approach I should take (i dont think this should happen even if im in dev mode)?

    Also (so i can be ontopic with the main post) i was thinking to load all the data when opening the webpage and store it (having a loading screen while doing that) then show the webpage but i have no idea what to start with (best practice to do that).

     POST http://localhost:3333/api/authorize 401 (Unauthorized) useAPIFetch.js 
    
        
        index.vue?t=1708783466118:75 [Vue warn]: Unhandled error during execution of setup function 
          at <Authors> 
          at <Index onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) {__v_skip: true} > > 
          at <Anonymous key="/" vnode= {__v_isVNode: true, __v_skip: true, type: {…}, props: {…}, key: null, …} route= {fullPath: '/', hash: '', query: {…}, name: 'index', path: '/', …}  ... > 
          at <RouterView name=undefined route=undefined > 
          at <NuxtPage> 
          at <Default ref=Ref< Proxy(Object) {…} > > 
          at <LayoutLoader key="default" layoutProps= {ref: RefImpl} name="default" > 
          at <NuxtLayoutProvider layoutProps= {ref: RefImpl} key="default" name="default"  ... > 
          at <NuxtLayout> 
          at <App key=3 > 
          at <NuxtRoot>
        
        Authors.vue:73 Uncaught (in promise) TypeError: Cannot read properties of null (reading 'userDefaultLibraryId')
            at Authors.vue:73:71
            at withAsyncContext (chunk-L5BJSZYY.js?v=6e0c88ac:4809:19)
            at setup (Authors.vue:73:25)
    

    Here is what i have now:

    <script lang="ts" setup >
    
    const { data: lib } = await useAPIFetch('/api/authorize' ,{method:"post", })
    
    const { data: books } = await useAPIFetch('/api/libraries/'+lib.value.userDefaultLibraryId+'/items?limit=8&sort=addedAt&desc=1' ,{method:"get", })
    
    </script>
    
    ...                   
            <div v-if="books.results" class="grid grid-cols-2 items-stretch sm:grid-cols-3 lg:grid-cols-4 gap-x-3 gap-y-10 sm:gap-x-5 sm:gap-y-8">
                <template v-for="book in books.results">
                      <Cards  :title="book.media.metadata.title" :href="'http://localhost:3333/item/' + book.id" duration="0" cover-image="http://localhost:3001/images/book_placeholder.jpg" category="TEST CATEGORIE" created-at="" description="TEST" />
                </template>
            </div>
    

    // composables/useAPIFetch.js
    
    import { useFetch } from "#app"
    
    
    // wrap useFetch with configuration needed to talk to our API
    export const useAPIFetch = async (path, options = {}) => {
      const config = useRuntimeConfig()
      
      // modify options as needed
      options.baseURL = "http://localhost:3333"
      options.headers = {Authorization: `Bearer ${config.apiSecret}`,}
      
      return useFetch(path, options)
    }
    

  2. I think you can try with the nuxt’s data fetching methods such as useFetch(), $fetch(), and useAsyncData(). Because these methods provide the pending value, you can use this to handle loading state.

    Example of using useFetch():

    <script setup>
    const { pending, data: posts } = useFetch('/api/posts')
    </script>
    
    <template>
      <!-- you will need to handle a loading state -->
      <div v-if="pending">
        Loading ...
      </div>
      <div v-else>
        <div v-for="post in posts">
          <!-- do something -->
        </div>
      </div>
    </template>
    
    

    Visit Nuxt’s Data fetching for more details

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search