0

I am trying to convert my vue app to nuxt app. In my vue app I used vue-slick-corousel with ease. But the same code with necessary modifications for nuxt, the corousel is not working on refresh. If I edit the template real time or navigate the app without refreshing the page, it works perfectly on second time visiting the page(s). Here is how I used vue-slick-corousel in my nuxt app

//nuxt.config.js
plugins: [
  { src: './plugins/vue-slick-carousel.js' }
],

Code in the plugin js file:

//vue-slick-carousel.js
import Vue from 'vue'
import VueSlickCarousel from 'vue-slick-carousel'

Vue.component('VueSlickCarousel', VueSlickCarousel)

And finally in the template:

<!-- CustomComponent.vue -->
<template>
  <div>
    <VueSlickCarousel :arrows="true" :dots="true">
      <div v-for="(cat, index) in categories" 
        :key="index"
        style="height: 20px; width: 10px; background-color: red; color: white"
      >
        {{cat.name}}
      </div>
    </VueSlickCarousel>
  </div>
</template>



<script>
  import VueSlickCarousel from 'vue-slick-carousel'
  import 'vue-slick-carousel/dist/vue-slick-carousel.css'
  // optional style for arrows & dots
  import 'vue-slick-carousel/dist/vue-slick-carousel-theme.css'
  export default {

    name: 'CustomComponent',
    data() {
      return {
        categories: []
      }
    },
    async fetch() {
      this.categories = await fetch(
        'https://*****************************/categories?limit=20'
      ).then(res => res.json())
    },
    components: {
      VueSlickCarousel
    },
  }
</script>

This is the error I am getting on refresh "TypeError: Cannot read property 'length' of undefined"

And whenever I am rendering the page again from clientside, the error goes away. Already tried bounding the container under

<client-only>

tried using a condition

v-if="slik.length" 

didn't work. How can I solve this issue?

kissu
  • 40,416
  • 14
  • 65
  • 133
adeab
  • 209
  • 1
  • 3
  • 13
  • How do you fetch `slik`? This one is undefined at some point hence the error with `length`. This is more of a lifecycle issue. Of course, it could be solved with some `slik?.length` but this would be greater to find why this is happening so far. – kissu Jun 05 '21 at 18:42

1 Answers1

1

EDIT: here is an explanation of the usage of $fetchState.pending helper.

  • fetch() is a non-blocking hook that will allow you to fetch data upon page/component loading
    • asyncData() is blocking but only when you navigate and not on initial render which can be annoying
    • you can make a blocking navigation with a combo of fetch() and a middleware
    • using skeletons is a nice way of having the user wait while feeling that the app is loading (Facebook-y)
  • your template is actually synchronous and will not wait for you to gather data, it is expecting to already have it right away. VueSlickCarousel is actually waiting for you to provide it an array of items. But upon initial render and before have fetched any data, you only do have categories: [] as setup in data()
  • $fetchState.pending is a handy helper that can tell us when the whole calls in fetch() are done. So if you will call 4 different APIs, it will equal to false only when all of the 4 calls will be done.
    • you can actually set it manually too with this.$fetchState.pending = true but this is forcing it and should be used when understood properly.
  • by writting <VueSlickCarousel v-if="!$fetchState.pending">, we do basically say wait until all of my things into fetch() to be done before mounting this component at all. This prevents any .length method issues because the component itself is not mounted until there is something to apply .length on.

Here is a small image of Nuxt's lifecycle, focused on fetch() hook. enter image description here


You should not mix async/await and then. Try to only use one of them (I do recommend the first one).

async fetch() {
  const response = await fetch(
    'https://*****************************/categories?limit=20'
  )
  const fetchedCategories = await response.json()
  console.log('categories', fetchedCategories)
  this.categories = fetchedCategories
},

Also, :key="index" is a bad practice because index is mutable in a v-for. Try to use an UUID from the API instead.

I'm pretty sure that those are not required neither:

  • import VueSlickCarousel from 'vue-slick-carousel'
  • components: { VueSlickCarousel },
kissu
  • 40,416
  • 14
  • 65
  • 133
  • Thanks. will careful about not using then and await together. but still the carousel is not working. it is showing "TypeError: Cannot read property 'length' of undefined". I wanted to know if there is any way to use the vue-slick-carousel in SSR nuxt. as in the documentation they said it was supposed to work perfectly in SSR – adeab Jun 07 '21 at 06:38
  • 1
    This have nothing to do with SSR so far. I did not tried this specific package but it looks like this is still a matter of data not being populated early on. Try this ``. Also, does the console log shows anything at all? – kissu Jun 07 '21 at 07:09
  • Thanks! if="!$fetchState.pending" actually worked I think! will do some more test and trials though but still no error anymore. That was very helpful! Can you explain the logic behind this?? and if you put this as answer I can tick mark that also. Again, thanks a lot! – adeab Jun 07 '21 at 18:30
  • I've updated my answer. I do hope that it explains a bit better what is happening and why is this solution working. Oh and as told previously, please provide a proper `id` to `:key` and not an iterative index. – kissu Jun 07 '21 at 22:57
  • 1
    sure. I have been using fetch hook to get data in nuxt, didn't know fetch could also be used in slick carousel in this way – adeab Jun 08 '21 at 01:15
  • 1
    At the end, it's just a matter on how/when/where you do fetch the data. Slick carousel will do it's job nonetheless, it just needs an array. – kissu Jun 08 '21 at 01:16