4

I am working on a carousel that provides an alternating src value to an image. This does work, however I cannot get React CSSTransition to work, since technically it is the same element just with a changing src value that is bound to a state variable.

Here is the code:

<CSSTransition
  classNames="carousel"
  in={true}
  appear={true}
  timeout={1000}
>
  <img
    src={this.state.imgLink}
    key={this.state.imgLink}
  />
</CSSTransition>

Any advice is greatly appreciated!

Cheers, Gabe

Gabor Szekely
  • 1,108
  • 5
  • 14
  • You should probably set an interval which updates the current image url in state and use that while rendering. I mean without any external library though. – Leela Venkatesh K Dec 14 '18 at 02:19
  • I am using an interval to alternate between src's, which is working, only there is no transition effect when the image changes. – Gabor Szekely Dec 14 '18 at 02:22
  • kivenky That is exactly what I am doing. I have `const { headerData, page } = this.state;` in my render method, I just didn't include it here. Will clarify the post so it makes more sense. – Gabor Szekely Dec 14 '18 at 02:40

2 Answers2

1

If you're in a state managed component you could use a switch variable in your state to tell CSSTransition when the src attribute is changing (by putting it on true) and then putting it back to false when the first transition is completed (with a onEntered callback):

<CSSTransition
  classNames="carousel"
  in={this.state.changing}
  onEntered={()=> this.setState({switch:false})}
  appear={true}
  timeout={1000}
>
  <img
    src={this.state.imgLink}
    key={this.state.imgLink}
  />
</CSSTransition>

That would work nice with a fading effect. But since your classNames is called carousel, I think you want to be able to move images around (like one exiting while another one entering). You won't be able to do that with only one <img> tag but you will by having one per image and unmounting them on exit (unmountOnExit prop) and managing them with an index variable on the state:

    {pictures.map((p, i) => (
      <CSSTransition
        key={p.id}
        in={i === this.state.index}
        classNames="carousel"
        timeout={1000}
      >
        <img
          src={p.url}
          className={i === this.state.index ? "fade-enter-done" : ""}
        />
      </CSSTransition>
    ))}
PaulCo
  • 1,398
  • 4
  • 17
  • 31
0

This may not be the official way but I found that if you wrap CssTransition with TransitionGroup and move the key from img to CssTransition it will work as you want it to. The enter and exit animation will run at the same time, perfect for images to slide in and out at the same time or crossfade, etc.

<TransitionGroup component={null}>
  <CSSTransition classNames="carousel" timeout={1000} key={this.state.imgLink}>
    <img src={this.state.imgLink} />
  </CSSTransition>
</TransitionGroup>

If you want one animation to start only after the other one has finished, wrap it with SwitchTransition.

Transition modes. out-in: Current element transitions out first, then when complete, the new element transitions in. in-out: New element transitions in first, then when complete, the current element transitions out.

type: 'out-in'|'in-out' default: 'out-in'

<SwitchTransition mode={"out-in"}>
  <CSSTransition classNames="carousel" timeout={1000} key={this.state.imgLink}>
    <img src={this.state.imgLink} />
  </CSSTransition>
</SwitchTransition>;