Andrea Casaccia Andrea Casaccia - 3 months ago 19
CSS Question

React animation synchronization

I have the following React component:

var Hello = React.createClass({

getInitialState: function() {
return {
visibility: 'visible'
};
},

toggleState: function() {
if (this.state.visibility === 'visible') {
this.setState({visibility: 'hidden'});
} else {
this.setState({visibility: 'visible'});
}
},

componentDidMount: function () {
var self = this;
setInterval(function() {
self.toggleState();
}, 5000);
},

render: function() {
return <div className={"animated " + (this.state.visibility === 'visible' ? 'fadeIn' : 'fadeOut')}>{this.state.visibility}</div>;
}

});


See the fiddle here.

Basically I am controlling both the string displayed and the component visibility using animate.css through the
state
property
visibility
.

Side effect is that, when the component is fading out, it shows "hidden" and then starts hiding. I would like to start the animation earlier, and only once it's done, change the string, so that "hidden" is never actually displayed.

What's the best way to achieve this kind of synchronization?

Answer

The best way to change state after hiding animation completed is to listen for a animationend event. Since you need to change text state only when your component has hidden visibility state you should change it right after hiding animation complete and change back to visible on start animation.

Extend state with text:

getInitialState: function() {
  return {
    visibility: 'visible',
    text: 'visible'
  }
}

So you should add listener in componentDidMount:

componentDidMount: function() {
  this.refs.animated.addEventListener('animationend', this.toggleText); // add ref="animated" element
  // rest code
}

Add toggleText method to change text state on animationend:

toggleText: function() {
  if (this.state.visibility === 'hidden') { // change only on hidden state
    this.setState({
      text: 'hidden'
    });
  }

}

And change text to visible right on show animation start, so:

toggleState: function() {
  if (this.state.visibility === 'visible') {
    this.setState({visibility: 'hidden'}); // text should not be changed immediately
  } else {
    this.setState({visibility: 'visible', text: 'visible'}); // change the text on show animation start
  }

}

Here's completed fiddle