React. How to animate transitions between React Router routes (II)
Learn how to create state-dependent animations when navigating between routes using React Router
In the previous article I told you how we could use the React Transition Group library in conjunction with React Router to create animations when navigating between different routes.
If you have not read that article and arrived here in another way, I recommend that you first take a look:
Since what I will tell here is based on the last example of that article. In it, I created a simple transition between the different routes of the application simulating a slider:
However, as you may have observed, it has a small problem. It does not matter the order in which we navigate since the animation we always see the same: the outgoing screen goes to the left and the one that enters appears on the right. Wouldn’t it be nice that when we move “backwards” (that is, to an earlier route) the animation is done in the opposite direction?
This is what I want to tell in this article: how to create animations for React Router that depend on the state.
Let’s see it!
😑 “Limitations” of React Transition Group
One of the “problems” that we are going to encounter when we try to create an animation that depends on an external state is the following limitation of React Transition Group:
Once a component has been assembled, its output animation cannot be changed.
Let’s see what this means.
In our example, we define the output animation as follows. In the App.js
file we specify the name of the class to apply with the transition ( slide
in this case):
const AnimatedSwitch = withRouter(({ location }) => (
<TransitionGroup>
<CSSTransition
key={location.key}
classNames="slide"
timeout={1000}
>
And in our style.css
file we define the output transition using the transform
property for each of the classes that the React Transition Group library adds:
.slide-exit {
position: absolute;
top: 0;
left: 0;
width: 100%;
transform: translateX(0%);
}.slide-exit-active {
transform: translateX(-100%);
}
This animation is perfect if we always navigate forward (as the outgoing route goes to the left).
However, the problem comes if we want to reverse the animation in case we are going to an earlier route since React Transition Group does not let us change it once the component has been assembled:
However, the library owner gives us a solution to avoid this problem.
ChildFactory to the rescue
As we have said we cannot modify the output animation of a component once it has been assembled.
However, React Transition Group provides us with the childFactory
property which allows us to wrap the descendant components of a TransitionGroup
even if they are leaving. You can read more about this property in the library documentation:
Therefore, we can have something similar to the following:
<TransitionGroup
childFactory={child => React.cloneElement(child, {
classNames: animationClassNames
})}
>
Being the animationClassNames
variable a variable that may have different values depending on the animation we need. Let’s see how!
🌎 Adding status to React Router routes
Once we know how we can modify the output animation of our routes, the following will be to think about how to calculate the meaning of our animation.
However, this is relatively simple since we can add a state to our routes as we navigate using the history
object provided by React Router. For example:
history.push({
pathname: routeGenerator(currentScreen + 1),
state: {previousScreen: currentScreen}
});
Thanks to this, we can store the value of the previous screen in the state
object so that we can calculate in which direction the navigation within our AnimatedSwitch
component should go.
🆒 Transitions between routes depending on the state
Now that we know how to maintain the state thanks to the state
object, let’s see how to decide the animation based on how we navigate.
To do this, the first thing we will do is modify the navigation menu of our original example to create a series of buttons that allow us to navigate cyclically:

As you can see on line 11, when I do history.push
using the history object provided by the HOC withRouter
, what I do is not only specify the route to which I want to navigate (cyclically), but also store it in the state
property screen from which I navigated.
On a visual level what we get now is:

Thanks to this change, in the AnimatedSwitch
component we will be able to the state
object of location
to know from which screen we come and, therefore, the animation to be performed.

In this new AnimatedSwitch
:
- In line 4 we extract the value of
previousScreen
from the route state in order to compare it withcurrentScreen
and decide which animation to add. - On line 9 we use the
childFactory
property of theTransitionGroup
component so that we can modify the animation of the route to which we have to exit.
That is to say. Suppose we are on the /first
route having navigated from /
. If we click on the Forward
button animation to “exit” will be slide-forward
(as before). But if we click on the Back
button the animation will change to slide-backward
thanks to the mix of the childFactory
property and the calculation of the previous route.
With all this, the only thing we need is to add the corresponding CSS to the slide-backward
animation:

And with that we will have our animation working correctly:
Final thoughts
I hope this article has helped you to deepen both the two libraries on which it is based: React Router and React Transition Group and that it will be easy from now on to give some “life” to the transitions between the different routes of your application.
If you want to continue deepening this topic I leave a couple of articles to complement everything I have told you.
Do you want to read more articles like this?
If you liked this article I encourage you to subscribe to the newsletter that I send every Sunday with similar publications to this and more recommended content: 👇👇👇