Looking at the component docs, react components has three items in their lifecycle: mount, unmount and update. React transition groups seems to be the most common way to apply transitions and animations in react. Can it be used on update aswell, (ie statechange) or only when an item is mounted/unmounted?
Yes you can add transition on state change. You need to provide a key to the child element which will change on state update.
From docs :
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.
Thus, you can do something like this :
class Container extends React.Component {
constructor(props) {
super(props);
this.state = {
number: 0
};
}
handleClick(e){
this.setState({number: this.state.number + 1});
}
render(){
return (
<div className='container'>
<CSSTransitionGroup transitionName="example" transitionAppear={true} transitionAppearTimeout={500} transitionEnterTimeout={500} transitionLeaveTimeout={300}>
<div className="number" key={this.state.number}>{this.state.number}</div>
</CSSTransitionGroup>
<button onClick={this.handleClick.bind(this)}>Click Me!</button>
</div>
)
}
}
React.render(<Container />, document.getElementById('container'));
Css
.example-enter {
opacity: 0.01;
}
.example-enter.example-enter-active {
opacity: 1;
transition: opacity 500ms ease-in;
}
.example-leave {
opacity: 1;
}
.example-leave.example-leave-active {
opacity: 0.01;
transition: opacity 300ms ease-in;
}
.example-appear {
opacity: 0.01;
}
.example-appear.example-appear-active {
opacity: 1;
transition: opacity .5s ease-in;
}
Here is fiddle.
Related
I made a toggle function that calls from the button and i dont understand why the Jobs component who receives the styles appears suddenly without without transitioning.
I want that the opacity.
I want the opacity to increase until the component displays slowly.
import React, { Component } from 'react';
import { withTranslation } from 'react-i18next';
import './Experience.css';
class Experience extends Component {
constructor() {
super()
this.state = { display: 'none', opacity: 0 }
this.toggle = this.toggle.bind(this)
}
toggle() {
console.log("ENTRO EN TOOGLE")
if (this.state.display === 'none') {
this.setState({ display: 'block' })
setTimeout(() =>
this.setState({ opacity: 1 }), 300
)
}
else {
this.setState({ opacity: 0 })
setTimeout(() =>
this.setState({ display: 'none' }), 900
)
}
}
styles = (e) => {
console.log(e)
}
render() {
const styles = this.state;
const { t } = this.props;
return (
<div>
<div className="card">
<div className="card-content">
<div className="row mt-top">
<div className="col xl4 l4 m6 s12">
<button onClick={this.toggle}>DESPLEGAR</button>
</div>
<Jobs style={styles}></Jobs>
</div>
</div>
</div>
</div>
);
}
}
export default withTranslation()(Experience);
what you're attempting is like wanting to call a function without calling it when you want an element to transition you need to call the transition CSS property
something like this.
.name {
opacity: 0;
transition: opacity 0.5s ease;
}
.name:hover {
opacity: 1;
}
I need some help because I can't seem to understand what I'm doing wrong...
Bellow is my render method from my component and the css used. What I'm trying to do is while the user is not authenticated to see a splash screen instead of the router.
It works but the problem is that there is no fadeIn effect when showing the splash component (mounting), but there is a fadeOut fadeIn effect when transitioning from the splash screen to the router...
render
render = () => {
let { user } = this.props;
return (
<TransitionGroup id='app' enter={true}>
{user.authenticated && <CSSTransition
in={true}
classNames='fade'
key={'router'}
timeout={{ enter: duration, exit: duration }}
>
<Router />
</CSSTransition>}
{!user.authenticated && <CSSTransition
in={true}
classNames='fade'
key={'splash'}
timeout={{ enter: duration, exit: duration }}
>
<Splash />
</CSSTransition>}
</TransitionGroup>
);
}
css
.fade-enter {
opacity: 0.01;
}
.fade-enter.fade-enter-active {
opacity: 1;
transition: opacity 500ms ease-in;
}
.fade-exit {
opacity: 1;
}
.fade-exit.fade-exit-active {
opacity: 0.01;
transition: opacity 500ms ease-in;
}
I am trying to map over state and add a transition to each element so that the elements appear on mounting the dom.
There are two components relevant to this: PricingPage and PricingCard.
The code for PricingPage is below:
import React, {Component} from 'react';
import PricingCard from './PricingCard';
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
class PricingPage extends Component {
constructor(props) {
super(props);
this.state={
pricingContent:[{title:'1Abstract Art Pricing', text:`Each piece of artwork is individually priced. I base this on how much work and effort I put into the picture, basically I'm just using my own criteria.`},{title:'2Abstract Art Pricing', text:`Each piece of artwork is individually priced. I base this on how much work and effort I put into the picture, basically I'm just using my own criteria.`},{title:'3Abstract Art Pricing', text:`Each piece of artwork is individually priced. I base this on how much work and effort I put into the picture, basically I'm just using my own criteria.`},{title:'4Abstract Art Pricing', text:`Each piece of artwork is individually priced. I base this on how much work and effort I put into the picture, basically I'm just using my own criteria.`},{title:'5Abstract Art Pricing', text:`Each piece of artwork is individually priced. I base this on how much work and effort I put into the picture, basically I'm just using my own criteria.`},{title:'6Abstract Art Pricing', text:`Each piece of artwork is individually priced. I base this on how much work and effort I put into the picture, basically I'm just using my own criteria.`}]
}
}
render () {
return (
<div className='pricing-page-wrapper'>
<div className='navbar-background'></div>
<h1 className='pricing-title'>Pricing</h1>
<ReactCSSTransitionGroup transitionName="pricing" transitionEnterTimeout={700} transitionLeaveTimeout={700}>
<div className='pricing-wrapper'>
{this.state.pricingContent.map((item,i) => {
return(
<PricingCard key={item.title} title={item.title} text={item.text} />
)
})}
</div>
</ReactCSSTransitionGroup>
</div>
)
}
}
export default PricingPage;
.pricing-page-wrapper{
min-height: 75vh;
width:80%;
margin: 0 auto;
.pricing-title{
color:#949494;
}
.pricing-wrapper{
opacity:1;
}
.pricing-enter {
height: 0px;
opacity: 0;
}
.pricing-enter.pricing-enter-active {
height: 90px;
opacity: 1;
transition: 700ms;
}
.pricing-leave {
opacity: 1;
height: 90px;
}
.pricing-leave.pricing-leave-active {
opacity: 0;
height: 0;
transition: 700ms;
}
}
PricingCard page:
import React, {Component} from 'react';
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
class PricingCard extends Component {
constructor(props){
super(props);
}
render () {
return (
<div className='pricing-card'>
<h3 className='pricing-card-title'>{this.props.title}</h3>
<div className='pricing-card-text'>{this.props.text}</div>
</div>
)
}
}
export default PricingCard;
.pricing-card{
border-radius: 15px;
border: 1px solid #949494;
padding: 20px;
height:90px;
margin: 10px 0 10px 0;
.pricing-card-title{
color:#949494;
}
.pricing-card-text{
color:#949494;
}
}
I cant seem to figure out what I'm doing wrong, any help would be appreciated.
You must use some unique key for an item in list, it's array index won't work. You can use item.title for example.
You must wrap all the elements group into single ReactCSSTransitionGroup, not every individual element.
ReactCSSTransitionGroup will track them by their keys, so it must be mounted and have all that unique keys for group elements. So take it out of PricingCard.render to PricingPage.render.
class PricingPage extends Component {
render () {
return (
<div className='pricing-page-wrapper'>
<div className='navbar-background'></div>
<h1 className='pricing-title'>Pricing</h1>
<ReactCSSTransitionGroup transitionName="pricing"
transitionEnterTimeout={700} transitionLeaveTimeout={700}>
{this.state.pricingContent.map((item,i) => {
return(
<PricingCard key={item.title}
title={item.title} text={item.text} />
)
})}
</ReactCSSTransitionGroup>
</div>
)
}
}
So i added transitionAppear={true} and used the following css selectors in my scss file:
.pricing-appear {
opacity: 0.01;
}
.pricing-appear.pricing-appear-active {
opacity: 1;
transition: opacity .5s ease-in;
}
The issue was that i wanted to animate on initial mounting of the components.
Apologies for the simplicity of this problem, but I am new to React and trying to implement a simple CSSTransitionGroup to hide/show an element, but with a fade, slide, etc. The documentation seems very straightforward, but for some reason the following code will not work for me.
While the .box toggles between being there or not, I do not see any of the CSS transitions in place on enter and on leave.
class Demo extends React.Component{
constructor(props) {
super(props);
this.state = { visible: false };
this.handleClick = this.handleClick.bind(this)
}
handleClick() {
this.setState({ visible: ! this.state.visible });
}
render() {
return <div>
<button onClick={this.handleClick}>{this.state.visible ? 'Slide up' : 'Slide down'}</button>
<ReactCSSTransitionGroup transitionName="example">
{ this.state.visible ? <div className='box' /> : null }
</ReactCSSTransitionGroup>
</div>
}
}
.box {
width: 200px;
height: 100px;
background: green;
margin-top: 10px; }
.example-enter {
height: 0px; }
.example-enter.example-enter-active {
height: 100px;
-webkit-transition: height .3s ease; }
.example-leave.example-leave-active {
height: 0px;
-webkit-transition: height .3s ease; }
I must be doing something wrong, as I can see this basic demo working in other online examples, but cannot replicate myself. Please let me know how to get my CSS transitions.
Thx internet
Did you check the console for error output? Because when I run your code I get this:
"Warning: Failed propType: transitionEnterTimeout wasn't supplied to
ReactCSSTransitionGroup: this can cause unreliable animations and
won't be supported in a future version of React. See
xxx for more
information. Check the render method of Demo."
"Warning: Failed
propType: transitionLeaveTimeout wasn't supplied to
ReactCSSTransitionGroup: this can cause unreliable animations and
won't be supported in a future version of React. See
xxx for more
information. Check the render method of Demo."
Adding the two missing props and it works fine.
class Demo extends React.Component{
constructor(props) {
super(props);
this.state = { visible: false };
this.handleClick = this.handleClick.bind(this)
}
handleClick() {
this.setState({ visible: ! this.state.visible });
}
render() {
return <div>
<button onClick={this.handleClick}>{this.state.visible ? 'Slide up' : 'Slide down'}</button>
<ReactCSSTransitionGroup transitionName="example" transitionEnterTimeout={300} transitionLeaveTimeout={300} >
{ this.state.visible ? <div className='box' /> : null }
</ReactCSSTransitionGroup>
</div>
}
}
transitionEnterTimeout and transitionLeaveTimeout both take a number representing the duration of the transition in milliseconds, hence "300" for a .3 second transition, which matches the CSS transitions you've specified.
I have a component that switches child components inside its ReactCSSTransitionGroup when its prop stage changes.
When the page loads the transitionAppear works fine but there is no transition leave or transition enter animation for when the prop changes / when the component inside ReactCSSTransitionGroup changes. When the stage changes from 'CONTENT' to 'BOOKING' the Content component should fade out while Booking component fades in.
Page component:
import React, {PropTypes} from 'react';
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
export default class Page extends React.Component {
static propTypes = { stage: PropTypes.string };
getComponent(stage) {
switch (stage) {
case 'CONTENT': {
return (
<Content />
);
}
case 'BOOKING': {
return (
<Booking />
);
}
}
}
shouldComponentUpdate(nextProps) {
return nextProps.stage !== this.props.stage;
}
render() {
return (
<div>
<ReactCSSTransitionGroup
transitionName='component-fade'
transitionAppear={true}
transitionEnter={true}
transitionLeave={true}
transitionEnterTimeout={500}
transitionAppearTimeout={500}
transitionLeaveTimeout={500}
component='div'
>
{this.getComponent(this.props.stage)}
</ReactCSSTransitionGroup>
</div>
);
}
}
CSS:
.component-fade-enter {
opacity: 0;
transform: translateY(+2em);
}
.component-fade-enter.component-fade-enter-active {
opacity: 1;
transform: translateY(0em);
transition: opacity 200ms ease-out, transform 200ms ease-in;
}
.component-fade-leave {
transform: translateY(0em);
opacity: 1;
}
.component-fade-leave.component-fade-leave-active {
transform: translateY(+2em);
opacity: 0;
transition: opacity 200ms ease-in, transform 200ms ease-in;
}
.component-fade-appear {
opacity: 0;
transform: translateY(+2em);
}
.component-fade-appear.component-fade-appear-active {
opacity: 1;
transform: translateY(0em);
transition: opacity 200ms ease-out, transform 200ms ease-in;
}
Figured out answer to my own question, just had to add a div wrapper to the components whose key changes as this.props.stage changes
<ReactCSSTransitionGroup
transitionName='component-fade'
transitionAppear={true}
transitionEnter={true}
transitionLeave={true}
transitionEnterTimeout={500}
transitionAppearTimeout={500}
transitionLeaveTimeout={500}
component='div'
>
<div key={this.props.stage}>
{this.getComponent(this.props.stage)}
</div>
</ReactCSSTransitionGroup>