It is common to add and remove elements from the DOM, such as items in a list, status messages (both inline and global shouts), tooltips, dialogs or modal windows, and even entire pages in a refreshless, single-page app. Instead of popping new content into the viewport immediately, it can sometimes be helpful to include animations to help the user keep track of what is changing especially when the changes are subtle. For our purposes today, I’ve exaggerated the transitions for that very reason.
Transition by toggling class
Transition using hidden attribute
React CSSTransitionGroup
Duration and child transitions
xxxxxxxxxx
<html>
<head>
<meta charset="utf-8">
<title>React Transitions</title>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/sass.js/0.4.0/sass.js"></script>
<script>
$.get('react.scss').done(function (sass) {
var css = Sass.compile(sass);
$('<style>').html(css).appendTo('head');
});
</script>
<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.2/backbone.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.8.3/moment.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/react/0.11.2/react-with-addons.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/react/0.11.2/jsxtransformer.js"></script>
<script type="text/jsx">
/** @jsx React.DOM */
window.Dispatcher = _.extend({}, Backbone.Events);
window.muon;
var local = JSON.parse(localStorage.getItem('react-demo')),
Model = Backbone.Model.extend({});
if (local) {
muon = new Model(local);
} else {
muon = new Model({});
}
var Something = React.createClass({
render: function() {
return (
<div className="something">Something</div>
);
}
});
var Dialog = React.createClass({
render: function() {
return (
<div className="dialog-overlay">
<div className="dialog-body">
<h1>This is a dialog, yo.</h1>
</div>
</div>
);
}
});
var App = React.createClass({
getInitialState: function () {
return _.extend({
demo_1: false,
demo_2: true,
demo_3: null,
demo_4: null,
}, this.props.model.toJSON());
},
componentDidMount: function () {
var component = this;
component.props.model.on('change', function (model) {
var json = model.toJSON();
component.setState(json);
localStorage.setItem('react-demo', JSON.stringify(json));
console.log('Changes saved to localStorage', json);
});
muon.set({app_mounted: true});
},
render: function () {
var Transition = React.addons.CSSTransitionGroup;
return (
<div className={this.getClasses()}>
<div className="main">
<h1 className="app-title">React CSS Transitions</h1>
<div className="demo-1">
<button className={this.getDemo1Classes()} onClick={this.toggleForDemo1}>Transition by toggling classes</button>
</div>
<div className="demo-2">
<button className="demo-2-button" onClick={this.toggleForDemo2}>Transition using hidden attribute</button>
<div className="demo-2-box" hidden={this.state.demo_2}>I was [hidden], but now I’m not.</div>
</div>
<div className="demo-3">
<button className="demo-3-button" onClick={this.toggleForDemo3}>Same transition with React</button>
<Transition transitionName="jacob">
{this.state.demo_3}
</Transition>
<h2 className="app-subheading">5 states when in the DOM</h2>
<ol className="app-list">
<li className="app-list-item">demo-3.jacob-enter</li>
<li className="app-list-item">demo-3.jacob-enter.jacob-enter-active</li>
<li className="app-list-item">demo-3</li>
<li className="app-list-item">demo-3.jacob-leave</li>
<li className="app-list-item">demo-3.jacob-leave-active</li>
</ol>
</div>
<div className="demo-4">
<button className="demo-4-button" onClick={this.toggleForDemo4}>Duration and child transitions</button>
</div>
</div>
<Transition transitionName="dialog">
{this.state.demo_4}
</Transition>
</div>
);
},
getDemo1Classes: function () {
var s = this.state;
return React.addons.classSet({
'demo-1-button': true,
'transition-me': this.state.demo_1
});
},
toggleForDemo1: function () {
this.setState({demo_1: !this.state.demo_1});
},
toggleForDemo2: function () {
this.setState({demo_2: !this.state.demo_2});
},
toggleForDemo3: function () {
if (!this.state.demo_3) {
this.setState({demo_3: (<Something />)});
} else {
this.setState({demo_3: null});
}
},
toggleForDemo4: function () {
if (!this.state.demo_4) {
this.setState({demo_4: (<Dialog />)});
} else {
this.setState({demo_4: null});
}
},
getClasses: function () {
var s = this.state;
return React.addons.classSet({
'app': true,
'dialog-open': s.dialog
});
}
});
React.renderComponent(<App model={muon} />, document.body);
</script>
</head>
<body>
</body>
</html>
Updated missing url //cdnjs.cloudflare.com/ajax/libs/react/0.11.2/JSXTransformer.js to //cdnjs.cloudflare.com/ajax/libs/react/0.11.2/jsxtransformer.js
https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.js
https://cdnjs.cloudflare.com/ajax/libs/sass.js/0.4.0/sass.js
https://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.js
https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.2/backbone.js
https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.8.3/moment.js
https://cdnjs.cloudflare.com/ajax/libs/react/0.11.2/react-with-addons.js
https://cdnjs.cloudflare.com/ajax/libs/react/0.11.2/JSXTransformer.js