Dynamic React animations

Did you know that you can dynamically change the transitionName of a React animation on the fly? This is more of a “hey look it works” thing then an actual revelation.

First, a quick primer/review taken from the React animation docs. The CSSTransitionGroup automatically adds classes to its children when they are added and removed.

<CSSTransitionGroup transitionName="example">
{items}
</CSSTransitionGroup>

In this case, a new item will be rendered with the .example-enter class. Immediately after render, the .example-enter-active class will be added.

By adding some matching CSS, you can cause the entry to be animated using CSS transitions.

.example-enter {
opacity: 0.01;
transition: opacity .5s ease-in;
}
.example-enter.example-enter-active {
opacity: 1;
}

CSSTransitionGroup also adds similar classes when elements leave.

Making the transition name dynamic

One cool aspect of CSSTransitionGroup is that you can adjust the name on the fly. Among many possibilities, this makes it very easy to dynamically control the direction of a sliding transition.

<CSSTransitionGroup transitionName={`slide-${direction}`}>
{items}
</CSSTransitionGroup>

In my case, I was dealing with a navigation component in which you could drill to various depths. Setting the name is simple, but calculating the desired direction requires a bit of state.

React.createClass({
// ...
componentWillReceiveProps(newProps) {
// `path` is an array of tree node indexes
const direction = newProps.path.length > this.props.path.length ? 'right' : 'left';
this.setState({direction});
},
render() {
// ...
return <CSSTransitionGroup transitionName={`slide-${this.state.direction}`}>
{/* ... nav pane ... */}
</CSSTransitionGroup>;
}
});

This isn’t bad, but I wanted to extract the state and moving parts into a self contained component. With this final product, the only prop you need to pass in is a numeric representation of your depth. The panes will slide transition from right to left as if moving forward when the number increases and vice versa when it decreases.

<SlideTransition depth={path.length}>
{/* ... nav pane ... */}
</SlideTransition>

The source of the final component is available in a Gist as well as a CodePen demo.


Originally published at esimmler.com.