Skip to content
This repository has been archived by the owner on Aug 19, 2022. It is now read-only.

Animate on change #474

Closed
arve0 opened this issue Dec 30, 2015 · 8 comments
Closed

Animate on change #474

arve0 opened this issue Dec 30, 2015 · 8 comments

Comments

@arve0
Copy link

arve0 commented Dec 30, 2015

Hi!
Is it possible to animate on state change?

I use this code

const bounceAnimation = Radium.keyframes({
  '25%': { transform: 'rotate(3deg) translateY(-5px)' },
  '50%': { transform: 'rotate(-2deg)' },
  '75%': { transform: 'rotate(1deg)' },
})
const style = {
  animation: 'x 0.8s ease',
  animationName: bounceAnimation
}

@Radium
class Score extends Component {
  render() {
    const props = this.props
    return <div className="Score" style={style}>
      Score: {props.points}
    </div>
  }
}

which only animates on first enter.

@ianobermiller
Copy link
Contributor

There isn't a super nice way to do this. I think you'll have to remove the animation when it completes and then add it again, see this example jsbin. You might be better off using something like react-motion instead.

@arve0
Copy link
Author

arve0 commented Dec 30, 2015

Thanks for the quick response. I took a similar approach using vanilla css:

render() {
    const points = this.props.points
    let className = 'Score'

    // animation class
    if (this.state.points != points) {
      className += ' Score--enter'
      setTimeout(() => this.setState({points: points}), 3020)
    }

    return <div className={className}>
      Score: {points}
    </div>
}

Edit: Fixed buggy setTimeout.

@arve0 arve0 closed this as completed Dec 30, 2015
@arve0
Copy link
Author

arve0 commented Jan 1, 2016

So, render better be pure. After I found the event animationend, I got my head around it:

/**
 * Animated component. Adds `animationClassName` when `animate` is true,
 * then removes `animationClassName` when animation is done (event 
 * `animationend` is triggered).
 *
 * @prop {string} className - Base class name.
 * @prop {string} animationClassName - Class added when `animate == true`.
 * @prop {bool} animate - Wheter to animate component.
 */
class Animated extends Component {
  constructor(props) {
    super(props)
    this.state = { animating: false, clearAnimationClass: false }
  }

  componentDidMount() {
    this.refs.root.addEventListener('animationstart', () => {
      this.setState({ animating: true, clearAnimationClass: false })
    })
    this.refs.root.addEventListener('animationend', () => {
      // send separate, animation state change will not render
      this.setState({ clearAnimationClass: true })  // renders
      this.setState({ animating: false, clearAnimationClass: false })
    })
  }

  shouldComponentUpdate(nextProps, nextState) {
    if (this.state.animating != nextState.animating){
      // do not render on animation change
      return false
    }
    return true
  }

  render() {
    let className = this.props.className

    if (this.props.animate && !this.state.clearAnimationClass) {
      className += ` ${this.props.animationClassName}`
    }

    return <span ref="root" className={className}>
      {this.props.children}
    </span>
  }
}

Usage:

<Animated className="Score-points"
  animationClassName="Score--bounce"
  animate={this.props.diff != 0}>
    Score: {this.props.points}
</Animated>

This could of course be useful in radium also.

@ianobermiller
Copy link
Contributor

I don't think animationend is very reliable, perhaps this would work better? https://facebook.github.io/react/docs/animation.html

@arve0
Copy link
Author

arve0 commented Jan 1, 2016

If I understand it correctly, ReactCSSTransitionGroup does only add enter and appear classes on new entries in lists, like showed in the example with items being an array. I could not make this work with changing integers (here a score which increments upon user input).

Regarding support, according to can i use and the spec, the event should be available if CSS animation is supported. Global support is 90% as of now, but I have no experience if this actually is the case.

@arve0
Copy link
Author

arve0 commented Jan 2, 2016

@ianobermiller
Copy link
Contributor

Sorry for the lack of context, I was referring to this quote:

it'll be fixed in 0.14 by asking you for durations. In 0.13.3 it's still an issue.

In this issue: facebook/react#1326

Way to go publishing a package for this, though!

@arve0
Copy link
Author

arve0 commented Jan 2, 2016

Way to go publishing a package for this, though!

I'm into the micro-modules-thingy :octocat:

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants