I tried to add page transitions to my app using ReactCSSTransitionGroup but it did not work. For some pages it worked but for some it did not. Many examples out there show how to do it with the React router. But since I use Meteor, I use a different router (FlowRouter).
Here's my render method :
render() {
return (
<div>
{this.props.content()}
</div>
);
}
Here's how I tried to add transitions :
<ReactCSSTransitionGroup
transitionName="pageTransition"
transitionEnterTimeout={500}
transitionLeaveTimeout={300}
transitionAppear={true}
transitionAppearTimeout={500}
>
{/* Content */}
{React.cloneElement(this.props.content(), {
key: uuid.v1(),
})}
</ReactCSSTransitionGroup>
The css :
//Page transition
.pageTransition-enter {
opacity: 0.01;
}
.pageTransition-enter.pageTransition-enter-active {
animation: fadeIn 1s ease-in;
}
.animation-leave {
opacity: 1;
}
.pageTransition-leave.pageTransition-leave-active {
animation: fadeIn 3s ease-in;
}
.pageTransition-appear {
opacity: 0.01;
}
.pageTransition-appear.pageTransition-appear-active {
animation: opacity 5s ease-in;
}
Any idea how to make this work?
I figured it out! Your CSS animations are trying to use fadeIn, but that's not a CSS property. You need to change it to opacity. Like so:
//Page transition
.pageTransition-enter {
opacity: 0.01;
}
.pageTransition-enter.pageTransition-enter-active {
animation: opacity 1s ease-in;
}
.animation-leave {
opacity: 1;
}
.pageTransition-leave.pageTransition-leave-active {
animation: opacity 3s ease-in;
}
.pageTransition-appear {
opacity: 0.01;
}
.pageTransition-appear.pageTransition-appear-active {
animation: opacity 5s ease-in;
}
try defining your inner component before return call:
render() {
const clonedElement = <div>{this.props.content()}</div>;
return (
<ReactCSSTransitionGroup transitionName="pageTransition" transitionEnterTimeout={500} transitionLeaveTimeout={300} transitionAppear={true} transitionAppearTimeout={500}>
{clonedElement}
</ReactCSSTransitionGroup>
);
}
Related
I am currently working on notification component in React. It is working except the transitions.. Somehow its not even adding class. I looked up some React animation examples and i do some research but i couldnt find anything useful. Especially article for React15. I didnt understand, this should work perfectly but its just showing and hiding text without any transitions.
import React, { Component } from 'react';
import CSSTransitionGroup from 'react-transition-group/CSSTransitionGroup';
import '../stylesheets/notification.less';
export default class Notifications extends Component {
render() {
return (
<CSSTransitionGroup transitionName="notifications" transitionEnterTimeout={300} transitionLeaveTimeout={300}>
<div className={this.props.type === 'error' ? 'notification-inner warning' : 'notification-inner success'}>
{this.props.type} {this.props.message}
</div>
</CSSTransitionGroup>
);
}
}
And CSS File...
.notifications {
background:#000;
}
.notifications-enter {
opacity: 0;
transform: translate(-250px,0);
transform: translate3d(-250px,0,0);
}
.notifications-enter.notifications-enter-active {
opacity: 1;
transition: opacity 1s ease;
transform: translate(0,0);
transform: translate3d(0,0,0);
transition-property: transform, opacity;
transition-duration: 300ms;
transition-timing-function: cubic-bezier(0.175, 0.665, 0.320, 1), linear;
}
.notifications-leave {
opacity: 1;
transform: translate(0,0,0);
transform: translate3d(0,0,0);
transition-property: transform, opacity;
transition-duration: 300ms;
transition-timing-function: cubic-bezier(0.175, 0.665, 0.320, 1), linear;
}
.notifications-leave.notifications-leave-active {
opacity: 0;
transform: translate(250px,0);
transform: translate3d(250px,0,0);
}
Make sure you have the key attribute set.
From the doc: https://facebook.github.io/react/docs/animation.html
Note:
You must provide the key attribute for all children of ReactCSSTransitionGroup, even when only rendering a single item. This is how React will determine which children have entered, left, or stayed.
I am trying to build a React component to handle fading in and fading out. In the following code, if I pass out as a prop to the component, it is disaplayed as hidden before animating out. I'm trying to have it fade in by default, then fade out when I pass in the out prop. Anyone see a solution to this problem?
import React from 'react';
import styled, { keyframes } from 'styled-components';
const fadeIn = keyframes`
from {
transform: scale(.25);
opacity: 0;
}
to {
transform: scale(1);
opacity: 1;
}
`;
const fadeOut = keyframes`
from {
transform: scale(1);
opacity: 0;
}
to {
transform: scale(.25);
opacity: 1;
}
`;
const Fade = styled.div`
${props => props.out ?
`display: none;`
: `display: inline-block;`
}
animation: ${props => props.out ? fadeOut : fadeIn} 1s linear infinite;
`;
function App() {
return (
<div>
<Fade><💅test></Fade>
</div>
);
}
export default App;
WebpackBin running example
The issue with your code is that you're setting the display property to none when props.out is true. That's why you're not seeing any animation, because before that can even start you've already hidden the component!
The way to do a fade out animation is to use the visibility property instead and transition that for the same amount of time as the animation takes. (see this old SO answer)
Something like this should solve your issues:
const Fade = styled.default.div`
display: inline-block;
visibility: ${props => props.out ? 'hidden' : 'visible'};
animation: ${props => props.out ? fadeOut : fadeIn} 1s linear;
transition: visibility 1s linear;
`;
const fadeIn = styled.keyframes`
from {
transform: scale(.25);
opacity: 0;
}
to {
transform: scale(1);
opacity: 1;
}
`;
const fadeOut = styled.keyframes`
from {
transform: scale(1);
opacity: 1;
}
to {
transform: scale(.25);
opacity: 0;
}
`;
const Fade = styled.default.div`
display: inline-block;
visibility: ${props => props.out ? 'hidden' : 'visible'};
animation: ${props => props.out ? fadeOut : fadeIn} 1s linear;
transition: visibility 1s linear;
`;
class App extends React.Component {
constructor() {
super()
this.state = {
visible: true,
}
}
componentDidMount() {
setTimeout(() => {
this.setState({
visible: false,
})
}, 1000)
}
render() {
return (
<div>
<Fade out={!this.state.visible}><💅test></Fade>
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://unpkg.com/styled-components/dist/styled-components.min.js"></script>
<div id="root" />
Note: Your fadeOut animation also went from 0 to 1 opacity, instead of the other way around. I've fixed that in the snippet too.
I'd like to move something bottom: +/- 100px.
So that when focused, it slides up. When unfocused, it slides back down.
I've created this React render() :
var component = (
<div key={"trayResponder_" + this.props.trayOpen} >
</div>
);
return(
<ReactCSSTransitionGroup transitionName="tray-responder">
{component}
</ReactCSSTransitionGroup>
);
And then I toggle it's key state, by updating this.props.trayOpen
And then my Less is like this :
.tray-responder-enter {
}
.tray-responder-enter-active {
.animation(slideUp 1s ease infinite )
}
.tray-responder-leave {
}
.tray-responder-leave-active {
.animation(slideDown 1s ease infinite )
}
.keyframes(slideUp;{
0% {transform: translateY(100%);}
50% {transform: translateY(-8%);}
65% {transform: translateY(4%);}
80% {transform: translateY(-4%);}
95% {transform: translateY(2%);}
100% {transform: translateY(0%);}
});
.keyframes(slideDown;{
0% {transform: translateY(-100%);}
50%{transform: translateY(8%);}
65%{transform: translateY(-4%);}
80%{transform: translateY(4%);}
95%{transform: translateY(-2%);}
100% {transform: translateY(0%);}
});
Which adopts from animation.less :
.keyframes(#name; #arguments) {
#-moz-keyframes #name { #arguments(); }
#-webkit-keyframes #name { #arguments(); }
#keyframes #name { #arguments(); }
}
.animation(#arguments) {
-webkit-animation: #arguments;
-moz-animation: #arguments;
animation: #arguments;
}
Unfortunately, this doesn't seem to work. Nothing occurs. No animation. Not really sure why.
Update
The trouble with ReactCSSTransitionGroup is that enter-active and leave-active occur simultaneously. Which doesn't seem to be a problem if you're toggling opacity. But if you're moving things up and down like I am, then you see both at the same time.
As seen here :
As much as I understand, CSS Transition is for enter and leave. You want animation on hover, which can probably be achieved by using :hover selector.
const TransitionDemo = React.createClass({
render : function () {
return(
<div className="demo">
<p>Some Text Here</p>
</div>
);
}
});
ReactDOM.render(<TransitionDemo trayOpen={1}/>, document.getElementById('root'));
//css
.demo {
height : 100px;
position : relative;
}
.demo p {
position : absolute;
bottom : 0px;
transition : all 1s ease;
}
.demo:hover > p{
bottom : 50px;
transition : all 1s ease;
}
See this pen : http://codepen.io/umgupta/pen/dNNLxL
I have this problem where the animation will only exit if the start animation is still in progress. Once the start animation finishes and I click another link it still adds the reverse class but only show a white page and the animation will not exit.
Here is the smoothstate call:
$(function(){
'use-strict';
var options = {
anchors: 'a',
prefetch: true,
blacklist: '.no-smoothState',
debug: true,
cacheLength: 2,
onStart: {
duration: 1000,
render: function($container) {
$container.addClass('is-exiting');
smoothState.restartCSSAnimations();
}
},
onReady: {
duration: 1000,
render: function($container, $newContent) {
$container.removeClass('is-exiting');
$container.html($newContent);
}
},
onAfter: function($container, $newContent) {
}
},
smoothState = $('#wrapper').smoothState(options).data('smoothState');
});
The HTML:
<div id="wrapper">
<div id="portfolio" class="portfolio">
<header>...</header>
<main id="content">
<section>
<h2>...</h2>
</section>
</main>
</div>
</div><!-- // wrapper -->
The CSS:
#wrapper #content {
animation-duration: 1s;
transition-timing-function: ease;
animation-fill-mode: forwards;
}
#wrapper #content {
animation-name: fadeInUp;
}
#wrapper.is-exiting #content {
animation-direction: alternate-reverse;
}
#keyframes fadeInUp {
0% {
opacity: 0;
transform: translateY(60px);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
Got it to work. If you use classes instead of ID's when targeting the animation it will start the exit animation.
i tried to create a simple transition with react transition group, but i can't get it to work- transitions aren't working.
i did used a unique key.
for the example i just did a simple 2 image fade in fade out component:
var ReactCSSTransitionGroup = React.addons.TransitionGroup;
var Image = React.createClass({
getInitialState: function () {
return ({imglink: 'http://belaumi.com/wp-content/uploads/2014/11/3D-Animated-Frog-Image.jpg', status: 1})
},
update: function () {
console.log(this);
if (this.state.status==1)
{
this.setState({ imglink: 'http://www.codefuture.co.uk/projects/imagehost/demo/di/KXY1/Image-b%C3%A9b%C3%A9-facebook-8.jpg', status:2})
} else {
this.setState({ imglink: 'http://belaumi.com/wp-content/uploads/2014/11/3D-Animated-Frog-Image.jpg', status:1})
}
} ,
render: function () {
return (
<div>
<div className='container'>
<button onClick={this.update.bind(this)}>Click</button>
<ReactCSSTransitionGroup transitionName="example">
<img key={this.state.status} src={this.state.imglink}/>
</ReactCSSTransitionGroup>
</div>
</div>
);
}
});
React.render(
<div>
<Image/>
</div>,
document.getElementById('reactbody')
)
</script>
i've also included proper css:
.example-enter {
opacity: 0.01;
transition: opacity .5s ease-in;
-webkit-transition: opacity .5s ease-in;
}
.example-enter.example-enter-active {
opacity: 1;
}
.example-leave {
opacity: 1;
transition: opacity .5s ease-in;
-webkit-transition: opacity .5s ease-in;
}
.example-leave.example-leave-active {
opacity: 0.01;
}
any idea why this is not working? the image does switch, but no fade..
thanks!
The addons name is CSSTransitionGroup:
var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
instead of
var ReactCSSTransitionGroup = React.addons.TransitionGroup;
(Notice the CSSTransitionGroup)
Working jsfiddle: http://jsfiddle.net/wvt30ocx/