How should I handle a leave animation in componentWillUnmount in React?
Asked Answered
P

2

33

I was wondering if anyone could provide some insight about how they handle leave animations in React.js. I have been using Greensock TweenMax and the enter animations work fine on componentDidMount, but I haven't found a reliable way to animate a component out.

My feeling is that it should go in componentWillUnmount, but React provides no callback mechanism for you to indicate when you are ready to let go of a component. Therefore the transition animation never completes since the animations are asynchronous to React. Instead, you see a tiny fraction of a second of animation, the component disappears, and is replaced by the next component animating in.

This is a problem I have struggled with since I started using React 9 months ago. I can't help but think there has to be a solution out there other than ReactCSSTransitionGroup which I find to be cumbersome and finicky, especially with react-router.

Prophylaxis answered 30/4, 2015 at 21:10 Comment(1)
You should do it in two steps where a component leaving is marked with some local state in the component, which triggers the animation. When the animation is complete, it can notify the parent to remove it completely.Denigrate
I
48

ReactTransitionGroup (upon which ReactCSSTransitionGroup is built) is the base component that allows asynchronous entering and leaving. It provides lifecycle hooks that you can use to hook into JS-based animations. The docs list the allowed hooks:

ReactTransitionGroup is the basis for animations. When children are declaratively added or removed from it (as in the example above) special lifecycle hooks are called on them. There are 3 ways to get starting using ReactCSSTransitionGroups:

import ReactCSSTransitionGroup from 'react-addons-css-transition-group' // ES6
var ReactCSSTransitionGroup = require('react-addons-css-transition-group') // ES5 with npm
var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup; // ES5 with react-with-addons.js

componentWillAppear(callback)

This is called at the same time as componentDidMount() for components that are initially mounted in a TransitionGroup. It will block other animations from occurring until callback is called. It is only called on the initial render of a TransitionGroup.

componentDidAppear()

This is called after the callback function that was passed to componentWillAppear is called.

componentWillEnter(callback)

This is called at the same time as componentDidMount() for components added to an existing TransitionGroup. It will block other animations from occurring until callback is called. It will not be called on the initial render of a TransitionGroup.

componentDidEnter()

This is called after the callback function that was passed to componentWillEnter is called.

componentWillLeave(callback)

This is called when the child has been removed from the ReactTransitionGroup. Though the child has been removed, ReactTransitionGroup will keep it in the DOM until callback is called.

componentDidLeave()

This is called when the willLeave callback is called (at the same time as componentWillUnmount).

Animation - Low-level API

In order to animate a child out, you'd need to start your animation in componentWillLeave and call the provided callback when the animation is complete. As an example, here's a JSFiddle showing a component that stagger-animates its children in and out: http://jsfiddle.net/BinaryMuse/f51jbw2k/

The relevant code for animating out is:

componentWillLeave: function(callback) {
  this._animateOut(callback);
},

_animateOut(callback) {
  var el = ReactDOM.findDOMNode(this);
  setTimeout(function() {
    TweenLite.to(el, 1, {opacity: 0}).play().eventCallback("onComplete", callback);
  }, this.props.animateOutDelay);
},
Illustrative answered 1/5, 2015 at 4:10 Comment(9)
Thank you so much for this explanation. This is the most clear and concise explanation I have ever found of animation within the component lifecycle.Prophylaxis
ReactTransitionGroup animation is just horribleMurk
Uncaught TypeError: React.findDOMNode is not a functionMurk
@Green: it's ReactDOM.findDOMNode nowadaysEvaporite
Spent most of the day on this. ReactTransitionGroup doesn't support interrupting the animation and then playing it in reverse, it always has to wait for the previous animation to end. Sucks if the users is clicking things quickly, would rather have no animations than unresponsive ones. If you're using any higher order components they won't pass down your life cycle methods (e.g. redux's connect)Fishbein
What about a slide mechanism for sliding out an UNMOUNTED component, while sliding in a new MOUNTED component? I can't seem to get this to work w/o trickery.Poon
@Fishbein , use React-Motion to fix this. It uses javascript to perform the animation but allows for a seamless transition. youtube.com/watch?v=1tavDv5hXpoNation
@jamesemanon github.com/chenglou/react-motion#transitionmotion- allows for this behaviour. It looks complicated at first, but once you figure it out, it's very flexible.Nation
For me ReactTransitionGroup doesn't even import, says i'm trying to load more than one copy of React. Following the sample example from React native page creates this error. Here's the problem: github.com/facebook/react-native/issues/3970.Vanscoy
N
3

Check out React-Motion

https://www.youtube.com/watch?v=1tavDv5hXpo

Cheng Lou is a developer on the React team.

He talks about the issues with the current ReactCSSTransitionGroup.

He has developed React-Motion for fixing this issue.

Although it doesn't use css transitions , it seems to perform well and is very deterministic. Where as ReactCSSTransitionGroup seems to be finicky as you cannot interrupt transitions.

Nation answered 17/8, 2016 at 18:22 Comment(3)
react-motion is hardly a replacement for CSSTransitionGroup, it's miles away from being humanly usable for effects that are otherwise trivial do do with CSS class transitions and keyframe animations.Charmainecharmane
I do agree, its fairly complicated to use.Nation
I found this FAAAR simpler to use than anything provided by React-Transition-Group. Thanks for pointing this out!Magisterial

© 2022 - 2024 — McMap. All rights reserved.