Reputation: 21
I am using react slick in my NextJS project to create a carousel of items. I have the showPrevArrow
and showNextArrow
to determine whether I am at the start of the carousel (to hide 'previous' arrow) or at the end (to hide 'next' arrow).
My code works for desktop screen sizes, but if I view it on smaller screen sizes (less than 1300px), the next button gets hidden at random parts of my carousel even if I have not yet reached the end of the items list. I think there is a problem with my computation for the showPrev and showNext arrows.
I need help figuring out why it works on desktop screen sizes but has encountered a problem when I make it responsive. Thanks!
Here is a snippet of my NextJS Code:
export default function Items({ items}) {
// other functions...
// Slider Functions
const [currentSlide, setCurrentSlide] = useState(0);
const sliderRef = useRef(null);
const settings = {
dots: false,
infinite: false,
speed: 500,
slidesToShow: 9,
slidesToScroll: 4,
beforeChange: (current, next) => setCurrentSlide(next),
responsive: [
{
breakpoint: 1290,
settings: {
slidesToShow: 6,
},
},
{
breakpoint: 1024,
settings: {
slidesToShow: 4,
},
},
{
breakpoint: 768,
settings: {
slidesToShow: 3,
},
},
{
breakpoint: 480,
settings: {
slidesToShow: 2,
},
},
],
};
const numItems = bannerCuisines.length;
const numSlidesToShow = settings.slidesToShow;
const numSlides = Math.ceil(numItems / settings.slidesToScroll);
const showPrevArrow = currentSlide > 0;
const showNextArrow = currentSlide + numSlidesToShow < numItems;
const handlePrevClick = () => {
if (sliderRef.current) {
sliderRef.current.slickPrev();
}
};
const handleNextClick = () => {
if (sliderRef.current) {
sliderRef.current.slickNext();
}
};
return (
<Layout>
// other HTML code here
<div className={styles.categories}>
{showPrevArrow && (
<button className={styles.prev} onClick={handlePrevClick}> Prev </button>
)}
<div className={styles.pane}>
<Slider {...settings} ref={sliderRef} arrows={false}>
{banner.map((category, index) => (
<div className={styles.container}>
// item contents here
</div>
))}
</Slider>
</div>
{showNextArrow && (
<button className={styles.next} onClick={handleNextClick}> Next </button>
)}
</div>
Upvotes: 0
Views: 1015
Reputation: 448
I totally understand the frustrations with react-slick when dealing with responsiveness. I've been through the same struggles. Instead of relying on the responsive property in settings, consider a different approach that dynamically calculates the number of slides based on the current viewport width. Here's what I suggest:
export default function Items({ items}) {
// other functions...
// Slider Functions
const [currentSlide, setCurrentSlide] = useState(0);
const sliderRef = useRef(null);
const getSlidesToShow = () => {
if (typeof window === 'undefined') return 9;
const width = window.innerWidth;
if (width < 480) return 2;
if (width < 768) return 3;
if (width < 1024) return 4;
if (width < 1290) return 6;
return 9;
};
const [slidesToShow, setSlidesToShow] = useState(getSlidesToShow);
useEffect(() => {
const handleResize = () => {
setSlidesToShow(getSlidesToShow());
};
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
const settings = {
dots: false,
infinite: false,
speed: 500,
slidesToShow: slidesToShow,
slidesToScroll: 4,
beforeChange: (current, next) => setCurrentSlide(next),
};
const numItems = bannerCuisines.length;
const numSlidesToShow = settings.slidesToShow;
const numSlides = Math.ceil(numItems / settings.slidesToScroll);
const showPrevArrow = currentSlide > 0;
const showNextArrow = currentSlide + numSlidesToShow < numItems;
const handlePrevClick = () => {
if (sliderRef.current) {
sliderRef.current.slickPrev();
}
};
const handleNextClick = () => {
if (sliderRef.current) {
sliderRef.current.slickNext();
}
};
return (
<Layout>
// other HTML code here
<div className={styles.categories}>
{showPrevArrow && (
<button className={styles.prev} onClick={handlePrevClick}> Prev </button>
)}
<div className={styles.pane}>
<Slider {...settings} ref={sliderRef} arrows={false}>
{banner.map((category, index) => (
<div className={styles.container}>
// item contents here
</div>
))}
</Slider>
</div>
{showNextArrow && (
<button className={styles.next} onClick={handleNextClick}> Next </button>
)}
</div>
Upvotes: 0