How to Replay a CSS3 Animation in Reactjs

How to replay a CSS3 animation in Reactjs

ReactJS uses key attribute to distinguish between elements in the diffing algorithm. So, the first time your component loads , react assumes it as new element and renders it accordingly. But next time it tries to render the same element with different data , react feels that it has the same structure and only replaces the new data with old data.

So to apply animations for every change, we need to tell react that this is a new component. This can be done by providing a key to the element with your animation class. And key can be randomly generated using any random number generator( I generally use shortid).

For working example, please refer: this

How to trigger a CSS animation on EVERY TIME a react component re-renders

Add a key like this:

function Card({ cardText }) {
return <div key={cardText} className="roll-out">{cardText}<div/>
}

In your code, when the div re-renders, react only changes its inner text. Adding a key will make react think it's a different div when the key changes, so it'll unmount it and mount again.

ReactJS, CSS and SVG animations, and re-rendering

React is reusing the elements, therefore the animations won't replay b/c they've already played for the current elements.

I think it's easier to resort to dom operations in this situation, versus some setState trickery.

https://codepen.io/guanzo/pen/vpdPzX?editors=0110

Store the refs to the 2 elements, then trigger the animations with JS.

class Component extends React.Component {
onClick() {
this.svgAnimate.beginElement()//triggers animation
this.square.style.animation = 'none';//override css animation
this.square.offsetHeight; /* trigger reflow */
this.square.style.animation = null; //fallback to css animation
}

render() {
console.log('rendering');
return (
<div onClick={() => this.onClick()}>
<svg>
<path
stroke="blue"
strokeWidth="10"
fill="transparent"
d="M50 10 a 40 40 0 0 1 0 80 a 40 40 0 0 1 0 -80"
strokeDasharray="251.2,251.2">
<animate
ref={(svgAnimate) => { this.svgAnimate = svgAnimate; }}
attributeType="css"
attributeName="stroke-dasharray"
from="0" to="251.2" dur="1s" />
</path>
</svg>
<div id="nonSvgBox"
ref={(square) => { this.square = square; }}
></div>
</div>
);
}
}

ReactDOM.render(<Component />, document.getElementById('app'));

How can I animate a react.js component onclick and detect the end of the animation

Upon clicks you can update the state, add a class and record the animationend event.

class ClickMe extends React.Component {
constructor(props) {
super(props)
this.state = { fade: false }
}
render() {
const fade = this.state.fade

return (
<button
ref='button'
onClick={() => this.setState({ fade: true })}
onAnimationEnd={() => this.setState({ fade: false })}
className={fade ? 'fade' : ''}>
Click me!
</button>
)
}
}

See the plnkr: https://next.plnkr.co/edit/gbt0W4SQhnZILlmQ?open=Hello.js&deferRun=1&preview

Edit: Updated to reflect current React, which supports animationend events.

Restart animation in CSS3: any better way than removing the element?

Just set the animation property via JavaScript to "none" and then set a timeout that changes the property to "", so it inherits from the CSS again.

Demo for Webkit here: http://jsfiddle.net/leaverou/xK6sa/
However, keep in mind that in real world usage, you should also include -moz- (at least).

React - animate mount and unmount of a single component

This is a bit lengthy but I've used all the native events and methods to achieve this animation. No ReactCSSTransitionGroup, ReactTransitionGroup and etc.

Things I've used

  • React lifecycle methods
  • onTransitionEnd event

How this works

  • Mount the element based on the mount prop passed(mounted) and with default style(opacity: 0)
  • After mount or update, use componentDidMount (componentWillReceiveProps for further updates)to change the style (opacity: 1) with a timeout(to make it async).
  • During unmount, pass a prop to the component to identify unmount, change the style again(opacity: 0), onTransitionEnd, remove unmount the element from the DOM.

Continue the cycle.

Go through the code, you'll understand. If any clarification is needed, please leave a comment.

class App extends React.Component{
constructor(props) {
super(props)
this.transitionEnd = this.transitionEnd.bind(this)
this.mountStyle = this.mountStyle.bind(this)
this.unMountStyle = this.unMountStyle.bind(this)
this.state ={ //base css
show: true,
style :{
fontSize: 60,
opacity: 0,
transition: 'all 2s ease',
}
}
}

componentWillReceiveProps(newProps) { // check for the mounted props
if(!newProps.mounted)
return this.unMountStyle() // call outro animation when mounted prop is false
this.setState({ // remount the node when the mounted prop is true
show: true
})
setTimeout(this.mountStyle, 10) // call the into animation
}

unMountStyle() { // css for unmount animation
this.setState({
style: {
fontSize: 60,
opacity: 0,
transition: 'all 1s ease',
}
})
}

mountStyle() { // css for mount animation
this.setState({
style: {
fontSize: 60,
opacity: 1,
transition: 'all 1s ease',
}
})
}

componentDidMount(){
setTimeout(this.mountStyle, 10) // call the into animation
}

transitionEnd(){
if(!this.props.mounted){ // remove the node on transition end when the mounted prop is false
this.setState({
show: false
})
}
}

render() {
return this.state.show && <h1 style={this.state.style} onTransitionEnd={this.transitionEnd}>Hello</h1>
}
}

class Parent extends React.Component{
constructor(props){
super(props)
this.buttonClick = this.buttonClick.bind(this)
this.state = {
showChild: true,
}
}
buttonClick(){
this.setState({
showChild: !this.state.showChild
})
}
render(){
return <div>
<App onTransitionEnd={this.transitionEnd} mounted={this.state.showChild}/>
<button onClick={this.buttonClick}>{this.state.showChild ? 'Unmount': 'Mount'}</button>
</div>
}
}

ReactDOM.render(<Parent />, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react-with-addons.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

React css webkit animation is not working after setState

I suggest it's a problem with your css rather than React. What you missed is a value for animation-iteration-count.

You can make it works by adding infinite to your -webkit-animation rule.


-webkit-animation:enemy 1s linear forwards infinite;

More information about animation can be found here: https://www.w3schools.com/cssref/css3_pr_animation.asp

React apply css classes dynamically

Well, here's an example. In short, I'd use css transitions, not keyframes for something as simple as this.

class App extends React.Component {  constructor(props) {    super(props)    this.state = {show: false}        this.show = this.show.bind(this)  }    show() {    this.setState(prevState => ({show: !prevState.show}))  }    render() {    return (      <div className={'wrapper' + (this.state.show ? ' show' : '')}>        <div>          <button onClick={this.show}>{this.state.show ? 'hide' : 'show'}</button>        </div>        <div className="one">one</div>        <div className="two">two</div>      </div>    )  }}
ReactDOM.render( <App />, document.getElementById('root'));
body {  margin: 0;}
.wrapper { overflow: hidden; white-space: nowrap;}
.one, .two { background: #333; border: 2px solid #787567; box-sizing: border-box; color: #fff; display: inline-block; font-family: arial; overflow: hidden; padding: 20px; text-align: center; transition: border 0.2s, padding 0.2s, width 0.2s;}
.one { width: 100%;}.two { border-width: 2px 0; padding: 20px 0; width: 0;}
.show .one, .show .two { border-width: 2px; padding: 20px; width: 50%;}
<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><div id="root"></div>


Related Topics



Leave a reply



Submit