vue-slick-carousel
vue-slick-carousel copied to clipboard
Mismatching childNodes vs. VNodes with responsive options (nuxtjs)
When using the responsive option and matching a breakpoint, after a page reload, an error is thrown :
[Vue warn]: The client-side rendered virtual DOM tree is not matching server-rendered content. This is likely caused by incorrect HTML markup, for example nesting block-level elements inside <p>, or missing <tbody>. Bailing hydration and performing full client-side render.
I'm using this configuration :
{
speed: 500,
arrows: false,
dots: true,
slidesToShow: 3,
slidesToScroll: 3,
responsive: [
{
breakpoint: 576,
settings: {
slidesToShow: 1,
slidesToScroll: 1
}
}
]
}
yes. I get this promlem too. Im waiting solution problem
I've tested using https://github.com/kyuwoo-choi/nuxt-vue-slick-carousel-example with responsive settings. And I can't reproduce this issue. @Brewal @PHPDevFrozenRain could you provide a demo I can reproduce?
Besides of that, I see nuxt server renders not considering responsive setting as nuxt can not know the client screen size. It's a limitation of this carousel.
the bug happens 2 div and more. Here is an example (uncomment responsive)
<vue-slick-carousel v-bind="settings"> <div>1</div> <div>2</div> </vue-slick-carousel>
settings:{
slidesToShow: 3,
arrows: true,
// responsive: [
// {
// breakpoint: 2500,
// settings: {
// slidesToShow: 3,
// slidesToScroll: 1,
// infinite: true,
// dots: true,
// arrows: true,
// }
// },
// {
// breakpoint: 991,
// settings: {
// slidesToShow: 2,
// slidesToScroll: 1,
// dots: true,
// arrows: true,
// }
// },
// {
// breakpoint: 767,
// settings: {
// slidesToShow: 1,
// slidesToScroll: 1,
// dots: true
// }
// },
// ]
},
Besides of that, I see nuxt server renders not considering responsive setting as nuxt can not know the client screen size. It's a limitation of this carousel.
yes. but it continious reproducing the bug and doesn't let use ssr. I noticed it on version 1.0.5 but I'm not sure about 1.0.3 version. In your example you use 1.0.2 version.
I have this issue with 1.0.2 (and 1.0.5 also). To reproduce, you need to have "universal" mode in Nuxt.js and refresh the page on some "breakpoint" from responsive setting. The error (warning) will show in console.
I temporarily solved this by wrapping the carousel with responsive configuration in
<client-only>...</client-only>
Same problem. Tell me how to fix it?
I still have no idea how to support responsive SSR. Yet, I reproduced this error and need to think of ways how to deal with it. I'd love to listen to the opinions.
Sadly I dont have so much time to consider all consequences of your code, but from quick check, I would start to avoid using created method for DOM manipulating.
In InnerSlider.vue::72 you got ssrInit() which is making preClones and postClones. It is not importent to have clones in SSR version, also you dont know the window sizes, so can not decide corectly based on "responsive".
Also in VueSlickCarousel.vue::105 is weird to call this.makeBreakpoints() in created methods. I guess it should be in mounted hook?
I understand the responsiveness of the carousel can cause some issue when used in conjunction of SSR. As @julpat said, you should have some options to prevent this issue (you should indeed be using the mounted event to render and patch the virtual DOM) but maybe it will take more efforts to make it work.
I didn't have the time either to look at the source code but I hope I will.
For now, maybe I will conditionally render multiple carousel based on the user agent using a library such as mobile-device-detect or just ignore the error !
are there going to be fixes? many people use carousel because of ssr.
Agree, maybe the Hotfix is removing "supports true SSR" from README.md 🤔
sure It should be fixed. I just have to find my time on it.
Same problem!!!
same here, will it be fixed?
I've found a workaround which works for SSR and does not add an additional performance burden for mobile devices.
It defines an initial mobile friendly this.settings.slidesToShow of 2 and an empty this.settings.responsive: [] . The required/desired responsive settings are applied once on VueSlickCarousel init.
Note: this.areResonsiveSettingsApplied === false check is used in order to prevent that this.responsiveSettings are applied multiple times through an init loop.
<template>
<div class="h-screen">
<VueSlickCarousel v-bind="settings" @init="initHandler">
<div
v-for="(value, index) in items"
:key="index"
class="h-40"
:class="[`bg-pink-${value}`]"
>
{{ value }}
</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: 'MyComponent',
components: { VueSlickCarousel },
data() {
return {
items: [100, 200, 300, 400, 500, 600, 700, 800, 900],
settings: {
dots: false,
infinite: true,
autoplay: true,
autoplaySpeed: 3000,
speed: 1000,
slidesToShow: 2,
slidesToScroll: 1,
initialSlide: 0,
cssEase: 'ease-in-out',
responsive: [],
},
responsiveSettings: [
{
breakpoint: 1201,
settings: {
slidesToShow: 4,
},
},
{
breakpoint: 993,
settings: {
slidesToShow: 3,
},
},
{
breakpoint: 769,
settings: {
slidesToShow: 2,
},
},
],
areResonsiveSettingsApplied: false,
}
},
methods: {
initHandler() {
console.log('> Handler : init')
if (this.areResonsiveSettingsApplied === false) {
this.applyResponsiveSettings()
}
},
applyResponsiveSettings() {
console.log('> Method : applyResponsiveSettings')
this.settings.responsive = this.responsiveSettings
this.settings.slidesToShow = 5
this.areResonsiveSettingsApplied = true
},
},
}
</script>
<style>
.slick-slider {
& .slick-arrow.slick-arrow {
@apply bg-red-600;
}
}
</style>
the solution from @dweiss-et works for me. although i'm curious about the missing @reInit event handler in your code example above.
@rizkysyazuli you are right there is an @reInit="reinitHandler unused event handler declaration in my example. I have removed it from the example because it's not required.
This worked for me.
<template>
<vue-slick-carousel v-if="showSlider" v-bind="sliderSettings">
...
</vue-slick-carousel>
</template>
<script>
export default {
data () {
return {
showSlider: true,
sliderSettings: {
... // do not include the responsive settings here
}
}
},
mounted () {
this.showSlider = false
this.$nextTick(() => {
this.sliderSettings.responsive = [{
breakpoint: 1024,
settings: {
...
}
}]
this.showSlider = true
})
}
}
</script>
@gullocean Thanks Its working but it flickers as on initial page load, 2 are loaded and then a single is switched in mobile.
Anyway to fix this?
If u are using Nuxt.js you can use device module to handle this error and don't loss SSR features on this plugin
slidesToShow: this.$device.isMobile ? 1 : 3, slidesToScroll: this.$device.isMobile ? 1 : 3,
This is not elegant at all but works as expected.
Using the solution provided by @dweiss-e AND ensuring that the # of items in the carousel stayed consistent across both the server and the client solved this issue for me.
Originally, due to a particular cache strategy I was using, the number of items in the carousel could change depending on whether it was rendered on the client or the server.
Having the same issue on 1.0.6. Using <client-only /> for now.
I did following instead:
computed: {
carouselOpts () {
switch (this.screenSize) {
case 'sm': return { centerMode: false, slidesToShow: 1, slidesToScroll: 1 }
case 'md': return { centerMode: false, slidesToShow: 2, slidesToScroll: 2 }
default: return { centerMode: true, slidesToShow: 3, slidesToScroll: 3 }
}
},
},
<vue-slick-carousel
:arrows="true"
v-bind="carouselOpts"
swipe-to-slide
>
this.screenSize is set first on the backend based on 'mobile-detect' package.