haunted85
haunted85

Reputation: 1671

Can't reproduce fade-in effect in React

I want to reproduce the effect I coded in this vanilla JS example in my React app.

This is my Sass

.item
    opacity: 0
    transition-property: opacity
    transition-timing-function: ease-in

.is-transitioning
    opacity: 1

the loop generating the images and their containers:

this.props.images.map((image, index) => <ImageContainer key={`img-${index}`} 
      image={image} 
      transitionDuration={Math.trunc(index * Math.random() * 1000) + 200} />
)

and finally the ImageContainer component:

    const ImageContainer = (props) => (

        <div className="item is-transitioning"
            style={{ transitionDuration: `${props.transitionDuration}ms` }}
        >
            <img src={`${props.image.path}`} />
        </div>
    );

     export default ImageContainer;

Even though the inline class is correctly applied and the css is there, I can't figure out why the effect doesn't show up.

Upvotes: 3

Views: 157

Answers (2)

Sunny Pun
Sunny Pun

Reputation: 726

(As said in another answer to this thread,) The issue is that the CSS (classes) didn't change, so the transition is "not needed", causing no animation.

For React people who wants to use transition over animation or other libraries, here is a "working" fiddle with a dirty hack: https://jsfiddle.net/s16nd2j5/

The trick is to add the class to <ImageContainer> in componentDidMount() with a setTimeout for 0ms.

setTimeout( _ => this.setState({ transitioning: true }), 0);

This kinda forces the state update to be "postponed" to another render, causing the "CSS class change" to take place.

P.S. it is a hack. The code smells when a setTimeout / setInterval is used like this.

P.P.S. The shuffle() part from OP's fiddle is omitted for simplicity.

Upvotes: 0

Temani Afif
Temani Afif

Reputation: 273970

The issue is that the is-transitioning is added from the beginning so your elements are already at opacity:1 and notihng will happen. You need to add the class in order to trigger the opacity change and see the transition.

Another way, in case you cannot add the class is to use animaton. Here is the JS example that you can convert to react:

Array.from(document.querySelectorAll('.item')).map((i, index) => {
  i.style.animationDuration = `${(index * Math.trunc(Math.random() * 1000)) + 200}ms`;
});
.container {
  display: flex;
}

.item {
  display: flex;
  justify-content:center;
  align-items: center;
  width: 1rem;
  height: 1rem;
  background-color: teal;
  padding: 2rem;
  margin-right: 1.2rem;
  border-radius: 10px;
  font-size: 2rem;
  color: white;
  opacity: 0;
  animation:change 2s forwards;
}
@keyframes change{
  to {
   opacity:1;
  }
}
<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
</div>

Simply keep the same code you wrote and replace transitionDuration with animationDuration and adjust the CSS.

Upvotes: 1

Related Questions