maxmarinich / react-alice-carousel

React responsive component for building content galleries, content rotators and any React carousels
MIT License
829 stars 91 forks source link

Changing ActiveIndex no working #319

Closed u-rogel closed 1 month ago

u-rogel commented 2 months ago

Thanks for the great component!

When I change activeIndex prop, the carousel is not updating accordingly. This is my example usage:

import { useEffect, useState } from 'react'
import AliceCarousel from 'react-alice-carousel'
import 'react-alice-carousel/lib/alice-carousel.css'

const slide = [
  'Hello',
  'World'
]

function App() {
  const [activeIndex, setActiveIndex] = useState(0);

  useEffect(() => {
    setTimeout(() => {
      setActiveIndex(1)
    }, 1000)
  }, [])

  return (
      <AliceCarousel
        activeIndex={activeIndex}
        items={slide.map((item) => {
          return (
            <div key={item} className='red'>
              <h3>{item}</h3>
            </div>
          )
        })}
      />
  )
}

export default App
jbro129 commented 1 month ago

The same issue is happening to me and my project so I created a new react project to props test the code from https://maxmarinich.github.io/react-alice-carousel/#custom-component. I modified the code a little bit, but the functionality should remains the same.

import React, { useState } from "react";
import AliceCarousel from "react-alice-carousel";
import "react-alice-carousel/lib/alice-carousel.css";

const items = [
  <img src="https://picsum.photos/1280/720" />,
  <img src="https://picsum.photos/1280/720" />,
  <img src="https://picsum.photos/1280/720" />,
];

const thumbItems = () => {
  return items.map((item) => (
    <div onDragStart={(e) => e.preventDefault()} className="thumb">
      {item}
    </div>
  ));
};

const App = () => {
  const [activeIndex, setActiveIndex] = useState(0);

  const slidePrev = () => setActiveIndex(activeIndex - 1);
  const slideNext = () => setActiveIndex(activeIndex + 1);
  const syncActiveIndexForSwipeGestures = (e) => setActiveIndex(e.item);

  const onSlideChanged = (e) => {
    syncActiveIndexForSwipeGestures(e);
    console.debug(
      `onSlideChanged => Item's position after changes: ${e.item}. Event:`,
      e
    );
  };

  const onUpdated = (e) => {
    console.debug(
      `onUpdated => Item's position after update: ${e.item}. Event:`,
      e
    );
  };

  return [
    <AliceCarousel
      mouseTracking
      activeIndex={activeIndex}
      disableDotsControls
      disableButtonsControls
      items={thumbItems(items)}
      onSlideChanged={onSlideChanged}
      onUpdated={onUpdated}
    />,
    <div className="carousel-buttons">
      <button onClick={slidePrev}>Prev</button>
      <button onClick={slideNext}>Next</button>
    </div>,
  ];
};

export default App;

I tested the code in a new project and it didn't work. Although slidePrev and slideNext changes the index with setActiveIndex, the index inside of the AliceCarousel does not change. onUpdated logs upon setActiveIndex being performed, but the e.item in the log remains the same: onUpdated => Item's position after update: 0. Event: {item: 0, slide: 0, itemsInSlide: 1, isNextSlideDisabled: false, isPrevSlideDisabled: true, …}

maxmarinich commented 1 month ago

Hello folks! The issue relates with React Flow. Every time you create new elements (mapping within rendering), the carousel is updated as expected. Solution: save items in the state (don't map while render) or set syncStateOnPropsUpdate === false.

import { useEffect, useState } from "react";
import AliceCarousel from "react-alice-carousel";
import "react-alice-carousel/lib/alice-carousel.css";

function createItems() {
  return ["Hello", "World"].map((item) => (
    <div key={item} className="red">
      <h3>{item}</h3>
    </div>
  ));
}

function App() {
  const [activeIndex, setActiveIndex] = useState(0);
  const [items, setItems] = useState(createItems());

  useEffect(() => {
    setTimeout(() => setActiveIndex(1), 1000);
  }, []);

  return (
    <AliceCarousel
      // syncStateOnPropsUpdate={false} uncomment this line if crete items in render
      activeIndex={activeIndex}
      items={items}
    />
  );
}

export default App;