I was wondering if anyone could provide some insight about how to achieve an animated component/page switch with React.js.
What i'd like to achieve is a component/page transition like the one on http://www.semplicelabs.com/ - a header that transitions opacity and margin-top and a content that transitions opacity.
When a new component/page is shown, the currently shown component/page should transition out before the new component/page transitioning in. What i have so far is a LayoutComponent
that renders a page component into a CSSTransitionGroup
:
import React from 'react/addons';
export default class LayoutComponent extends React.Component {
constructor(props) {
super(props);
this.state = { page: '' };
},
setPage(page) {
this.setState({ page });
}
render() {
return (
<React.addons.CSSTransitionGroup transitionName='page'>
{this.state.page}
</React.addons.CSSTransitionGroup>
);
}
}
I also have two page components, FirstPage
and SecondPage
.
import React from 'react';
export default class FirstPage extends React.Component {
render() {
return (
<div>
<header className='header'>
<div className='container'>
First Header
</div>
</header>
<div className='content'>
<div className='container'>
First Content
</div>
</div>
</div>
);
}
}
The only differences between SecondPage
code and FirstPage
code are the contents in the .container
divs and the classes name.
What i then tried to do is add a leave transition with .8s
duration and an enter transition with both .8s
duration and delay. The main problem i see is that the new page component is mounted before the leave transition of the old one has finished. This is my current CSS:
.page-enter {
background-color: #f2f2f2;
transition: background-color .8s linear .8s;
}
.page-enter-active {
background-color: #f2f1f1;
}
.page-leave {
background-color: #f2f1f1;
transition: background-color .8s linear;
}
.page-leave-active {
background-color: #f2f2f2;
}
.page-enter .header {
margin-top: -80px;
opacity: 0;
transition: opacity .8s ease-in-out .8s;
transition: margin-top .8s ease-in-out .8s;
}
.page-enter-active .header {
margin-top: 0;
opacity: 1;
}
.page-leave .header {
margin-top: 0;
opacity: 1;
transition: opacity .8s ease-in-out;
transition: margin-top .8s ease-in-out;
}
.page-leave-active .header {
margin-top: -80px;
opacity: 0;
}
.page-enter .content {
opacity: 0;
transition: opacity .8s ease-in-out .8s;
}
.page-enter-active .content {
opacity: 1;
}
.page-leave .content {
opacity: 1;
transition: opacity .8s ease-in-out;
}
.page-leave-active .content {
opacity: 0;
}
I know i could animate the initial mounting with transitionAppear={true}
- but that doesn't help with the problem of the new component being mounted before the old one is transitioned out.
This is a problem I have struggled with for a few days and I can't find a solution for.
Some code to play around with: https://jsfiddle.net/gonsfx/xva2g6oo/