YIZHUANG / react-multi-carousel

A lightweight production-ready Carousel that rocks supports multiple items and server-side rendering with no dependency. Bundle size 2kb.
MIT License
1.25k stars 286 forks source link

Not getting proper index for infinite=true #407

Open Richa-rani02 opened 9 months ago

Richa-rani02 commented 9 months ago

DESCRIPTION After change returns previousSlide and currentSlide which is working fine in case infinite=false However, when infinite={true} is used, the current index doesn't seem correct

What i am trying to achieve: want to track current index and next Index when arrow icon is clicked

Steps To Reproduce https://codesandbox.io/s/multicarousal-demo-9vzw96?file=/src/App.js

Hosted Application https://9vzw96.csb.app/

da8ah commented 9 months ago

I'm wondering the same. I need to get the index of the current element after arrows are clicked with infinite & centerMode true.

da8ah commented 9 months ago

Hi @Richa-rani02, I was able to do a workaround when infinite & centerMode true. It's just a hunch, so I hope I'm not mistaken.

If the carouse it's set to run ltr indexes will go increasily from 3 to the end. Note: If you set rtl it will behave differently. Let's take for example an array of 4 elements [0,1,2,3]

const arr = [0,1,2,3]

Right side (arrow): in the carousel the arr it will start at 3 as 0 index because makes copies of the other elements (2 each side I believe) But we need to set currentSlide - 2 so we can hit the activeSlide with 1 element to the right from the beginning to use centerMode. And then we need to restart with a condition currentSlide - 2 === dataSize (whitout - 1 because de displacement) then equal to 0. // 3,4,5,6 // 1,2,3,0

Left side (arrow): for the left arrow, when it's in reverse, it will start at index 1 then 0 and then it will decrease from the arr last element up to 2. So we need to subtract 2 when currentSlide >= dataSize and <= 2, otherwise we should subtract dataSize - 2. // 1,0,3,2 -> carousel index sequence // 3,2,1,0 -> desired indexes

I made this function that automatically does it for you (changeSlide):

    const responsive = {
        superLargeDesktop: {
            // the naming can be any, depends on you.
            breakpoint: { max: 4000, min: 3000 },
            items: 1
        },
        desktop: {
            breakpoint: { max: 3000, min: 1024 },
            items: 1
        },
        tablet: {
            breakpoint: { max: 1024, min: 464 },
            items: 1
        },
        mobile: {
            breakpoint: { max: 464, min: 0 },
            items: 1
        }
    };
    const [activeIndex, setActiveIndex] = useState(0)
    const images = [
        {
            src: slide1,
            alt: "",
        },
        {
            src: slide2,
            alt: "",
        },
        {
            src: slide3,
            alt: "",
        },
        {
            src: slide4,
            alt: "",
        },
    ]
    const changeSlide = (previousSlide: number, currentSlide: number, dataSize: number) => {
        let activeSlide = 0
        // right arrow
        if (previousSlide < currentSlide) activeSlide = currentSlide - 2 === dataSize ? 0 : currentSlide - 2
        // left arrow
        else activeSlide = currentSlide + (currentSlide <= dataSize && currentSlide >= 2 ? -2 : dataSize - 2);
        setActiveIndex(activeSlide)
    }

As for the carousel I did this:

<Carousel
    infinite
    autoPlay
    centerMode
    responsive={responsive}
    className="w-full h-[70%] owl-carousel owl-theme text-center"
    itemClass="px-1 flex justify-center"
    keyBoardControl={true}
    // changeSlide(previousSlide, currentSlide, dataSize = images.length)
    afterChange={(previousSlide, { currentSlide }) => changeSlide(previousSlide, currentSlide, images.length)}
>
    {images.map((img, i) => (
        <div
            key={`slide-${i}`}
            className={`relative ${activeIndex !== i ? "w-[90%]" : "w-full"} h-full rounded-[10px] flex justify-center items-center bg-transparent shadow-[10px_40px_10px_5px_black]`}
        >
            {activeIndex !== i ?
                <img
                    className='pointer-events-none object-contain rounded-[10px] opacity-10'
                    src={img.src}
                    alt={img.alt}
                />
                :
                <img
                    key={`slide-img-${activeIndex}`}
                    className='object-contain rounded-[10px]'
                    src={img.src}
                    alt={img.alt}
                />
            }
        </div>
    )
    )}
</Carousel>

I hope this help you and others too!