1

I am trying to create an auto image slider with React and ReactTransitionGroup but I can't get animations to work. The image will change, but the transition effect won't play. I'm assuming it's the CSS because the class names do get added/removed.

Component

const ImgSlideshow = (props) => {

  const images = [
    'https://images.unsplash.com/photo-1593642634315-48f5414c3ad9?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1050&q=80',
    'https://images.unsplash.com/photo-1593642702821-c8da6771f0c6?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1189&q=80',
    'https://images.unsplash.com/photo-1593642532781-03e79bf5bec2?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=634&q=80',
    'https://images.unsplash.com/photo-1593642634443-44adaa06623a?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=925&q=80',
    'https://images.unsplash.com/photo-1593642634524-b40b5baae6bb?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1189&q=80'
  ]

  const [slide, setSlide] = useState(0);


  useEffect(() => {
    const slideshowTimer = setInterval(() => {
      ((slide + 1) > images.length - 1) ? setSlide(0) : setSlide(slide + 1)
    }, 3000)

    return () => clearInterval(slideshowTimer)

  })
  
  return (
    <div className={styles.slideshow}>
      <SwitchTransition>
        <CSSTransition key={slide} timeout={200} classNames='slideshowImg'>
          <img src={images[slide]} className="slideshowImg"></img>
        </CSSTransition>
      </SwitchTransition>
      {props.children}
    </div>
  )
}

CSS

.slideshowImg-enter {
  opacity: 0;
  transform: translateX(-100%);
}
.slideshowImg-enter-active {
  opacity: 1;
  transform: translateX(0%);
}
.slideshowImg-exit {
  opacity: 1;
  transform: translateX(0%);
}
.slideshowImg-exit-active {
  opacity: 0;
  transform: translateX(100%);
}
.slideshowImg-enter-active,
.slideshowImg-exit-active {
  transition: opacity 500ms, transform 500ms;
}
Jordan Baron
  • 141
  • 1
  • 12

1 Answers1

0

There are a couple of issues that I see.

  1. You don't need to specify the className from the classNames prop on the child element that is being transitioned. If you have styles attached to this class then I would recommend you change it to something else to avoid confusion, but I don't think that is affecting your transitions.

  2. You are setting transitions to 500ms but only allowing the transition group 200ms to complete the transition.

  3. It also looks like you are just changing the image source instead of using a new element each time.

I have a working code sandbox here

I think you can achieve the desired result with this refactor:

const ImgSlideshow = (props) => {
  const images = [
    "https://images.unsplash.com/photo-1593642634315-48f5414c3ad9?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1050&q=80",
    "https://images.unsplash.com/photo-1593642702821-c8da6771f0c6?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1189&q=80",
    "https://images.unsplash.com/photo-1593642532781-03e79bf5bec2?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=634&q=80",
    "https://images.unsplash.com/photo-1593642634443-44adaa06623a?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=925&q=80",
    "https://images.unsplash.com/photo-1593642634524-b40b5baae6bb?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1189&q=80"
  ];

  const [slide, setSlide] = useState(0);

  const imageElements = images.map((img, i) => {
    return <img src={img} key={i} alt={`slideshow ${i+1}`} />;
  });

  useEffect(() => {
    const slideshowTimer = setInterval(() => {
      slide + 1 > images.length - 1 ? setSlide(0) : setSlide(slide + 1);
    }, 3000);

    return () => clearInterval(slideshowTimer);
  });

  return (
    <div>
      <SwitchTransition>
        <CSSTransition key={slide} timeout={500} classNames="slideshowImg">
          {imageElements[slide]}
        </CSSTransition>
      </SwitchTransition>
      {props.children}
    </div>
  );
};

My snippet uses the map function to create an array of img elements, each with a src that is correspondent to the index of the images array. This way you will have multiple elements to transition in between. Right now you only have one image element, and the react-transition-group can't put an animation on the changing of the image src (afaik).

PsiKai
  • 1,803
  • 1
  • 5
  • 19