Dae
Dae

Reputation: 21

Hide react slick next button when reached the end of the carousel for all screen sizes

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

Answers (1)

Sajed
Sajed

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

Related Questions