P.Brian.Mackey P.Brian.Mackey - 4 months ago 29
jQuery Question

Create a loading animation that works in react

Fiddle

var Hello = React.createClass({
getInitialState: function() {
return {
gridIsLoaded: true
}
},

animate(self) {
console.log('animating...');
$('#loadingDiv').animate({'opacity': '0'}, 500, function(){
$('#loadingDiv').animate({'opacity': '.5'}, 500, function(){
$('#loadingDiv').animate({'opacity': '1'}, 500, function(){
//if(!self.state.gridIsLoaded){
self.animate();
//}
});
});
});
},

getData() {
console.log('getData called.');
var artificialTimeout = 5000;
var self = this;
self.animate(self);

$.ajax({

url:'/echo/js/?js=hello%20world!',
complete: function (response) {
console.log(response.responseText);
setTimeout(function() {
self.setState({gridIsLoaded: true});
}, artificialTimeout);

},
error: function () {
console.log('there was an error!');
self.setState({gridIsLoaded: true});
},
});
return false;
},

handleClick(){
console.log('handleClick');
this.getData();
this.setState({gridIsLoaded: false});
},

render: function() {
var loadingJsx;
if (!this.state.gridIsLoaded) {
loadingJsx = (
<div id="loadingDiv" style={{ position:'relative', 'width': '100%', 'textAlign': 'center'}} className="text-center">
Loading... please wait
</div>);
};

return <div>
{loadingJsx}
<div>
<input type="button" value="Submit" onClick={this.handleClick} />
</div>
</div>;
}
});

ReactDOM.render(
<Hello name="World" />,
document.getElementById('container')
);


When I click submit this says "Loading please wait..." as it should. I want the opacity to animate in and out while loading is displayed. That is not working. Then if I click submit again it should do the same thing.

How can I get the animation to work?

Simple case outside react works.

Answer

A more 'react' way to do this would be to toggle a class on an element when you want to animate it. So in this case, we can conditionally apply an animate class when the grid has not loaded (though it's redundant in this case as that's the only time it shows).

loadingJsx = (
  <div id="loadingDiv" className={this.state.gridIsLoaded ? 'text-center' : 'text-center animate'}>
    Loading... please wait
  </div>);

Then I've separated out the css to apply to #loadingDiv.animate, though an alternate approach would be to toggle a style object. I suppose you could also continuously update the opacity property of a style object, which is closer to what you're doing, but it seems dirtier imo.

#loadingDiv.animate {
  opacity: 0;
  animation: fadeInOut 1s infinite;
}

@keyframes fadeInOut {
  0% { opacity: 0; }
  50% { opacity: 1; }
  100% { opacity: 0; }
}

updated fiddle

Comments