React. Cómo animar las transiciones entre rutas de React Router (II)
Aprende a crear animaciones dependientes del estado al navegar entre rutas empleando React Router
English version: https://medium.com/@ger86/react-how-to-animate-transitions-between-react-router-routes-ii-edb2cff0c86
En el artículo anterior os contaba la forma en que podíamos emplear la librería React Transition Group en conjunción con React Router para crear animaciones a la hora de navegar entre distintas rutas.
Si no habéis leído ese artículo y habéis llegado aquí de otro modo, os recomiendo que primero le echéis un vistazo:
Ya que lo que aquí contaré está basado en el último ejemplo de ese artículo. En él, creé una transición sencillita entre las distintas rutas de la aplicación simulando un slider:
Sin embargo, como quizás hayáis observado tiene un pequeño problema. No importa el orden en el que naveguemos ya que la animación que vemos siempre la misma: la pantalla saliente se va por la izquierda y la que entra aparece por la derecha. ¿No estaría bien que cuando nos desplazamos “hacia atrás” (es decir, a una ruta anterior) la animación se realice en sentido contrario?
Es justo esto lo que quiero contar en este artículo: cómo crear animaciones para React Router que dependan del estado.
¡Vamos a verlo!
😑 “Limitaciones” de React Transition Group
Uno de los “problemas” con los que nos vamos a topar cuando intentemos conseguir crear una animación que dependa de un estado externo es la siguiente limitación de React Transition Group:
Una vez que un componente se ha montado, su animación de salida no puede cambiarse.
Veamos qué significa esto.
En nuestro ejemplo, nosotros definimos la animación de salida del siguiente modo. En el archivo App.js
especificamos el nombre de la clase a aplicar con la transición ( slide
en este caso):
const AnimatedSwitch = withRouter(({ location }) => (
<TransitionGroup>
<CSSTransition
key={location.key}
classNames="slide"
timeout={1000}
>
Y en nuestro archivo style.css
definimos la transición de salida empleando la propiedad transform
para cada una de las clases que va añadiendo la librería React Transition Group:
.slide-exit {
position: absolute;
top: 0;
left: 0;
width: 100%;
transform: translateX(0%);
}.slide-exit-active {
transform: translateX(-100%);
}
Esta animación es perfecta si siempre navegamos “hacia adelante” (pues la ruta saliente se va por la izquierda).
Sin embargo, el problema viene si quisiéramos invertir la animación en el caso de que estemos yendo a una ruta anterior ya que React Transition Group no nos deja cambiarla una vez que el componente ha sido montado:
Sin embargo, la propieda librería nos da una “solución” para esquivar este problema.
ChildFactory al rescate
Como hemos dicho no podemos modificar la animación de salida de un componente una vez que se ha montado.
Sin embargo, React Transition Group nos proporciona la propiedad childFactory
la cual nos permite envolver a los componentes descendientes de un TransitionGroup
aunque estén saliendo. Podéis leer más sobre esta propiedad en la documentación de la librería:
Por tanto, podemos tener algo similar a lo siguiente:
<TransitionGroup
childFactory={child => React.cloneElement(child, {
classNames: animationClassNames
})}
>
Siendo la variable animationClassNames
una variable que podrá tener distintos valores en función de la animación que necesitemos. Vamos a ver cómo!
🌎 Añadiendo estado a las rutas de React Router
Una vez que sabemos la forma en que podemos modificar la animación de salida de nuestras rutas lo siguiente será pensar la forma de calcular el sentido de nuestra animación.
Sin embargo, esto es relativamente sencillo ya que podemos añadir un estado a nuestras rutas a medida que navegamos empleando el objeto history
proporcionado por React Router. Por ejemplo:
history.push({ pathname: routeGenerator(currentScreen + 1), state: {previousScreen: currentScreen}});
Gracias a esto, podemos almacenar en el objeto state
el valor de la pantalla anterior de modo que podamos calcular en qué sentido debería ir la navegación dentro de nuestro componente AnimatedSwitch
.
🆒 Transiciones entre rutas dependiendo del estado
Ahora que ya sabemos mantener el estado gracias al objeto state
, veamos cómo decidir la animación en función de cómo naveguemos.
Para ello, lo primero que haremos será modificar el menú de navegación de nuestro ejemplo original para crear una serie de botones que nos permitan navegar de forma cíclica:

Como podéis ver en la línea 11, cuando hago history.push
empleando el objeto history
proporcionado por el HOC withRouter
lo que hago no sólo es especificar la ruta hacia la que quiero navegar (de forma cíclica), sino que almaceno en la propiedad state
la pantalla desde la que navegué.
A nivel visual lo que obtenemos ahora es:

Gracias a este cambio, en el componente AnimatedSwitch
podremos al objeto state
de location
para saber de qué pantalla venimos y, por tanto, la animación que hay que realizar.

En este nuevo AnimatedSwitch:
- En la línea 4 extraemos del estado de la ruta el valor de
previousScreen
de cara a compararlo concurrentScreen
y decidir qué animación añadir. - En la línea 9 empleamos la propiedad
childFactory
del componenteTransitionGroup
de cara a que podamos modificar la animación de la ruta a la que toca salir.
Es decir. Supongamos que nos encontramos en la ruta /first
habiendo navegado desde /
. Si pulsamos sobre el botón Forward
la animación para “salir” será slide-forward
(como antes sucedía). Pero si pulsamos sobre el botón Back
la animación cambiará a slide-backward
gracias a la mezcla de la propiedad childFactory
y el cálculo de la ruta previa.
Con todo ello, lo único que nos falta es añadir el CSS correspondiente a la animación slide-backward
:

Y con ello ya tendremos nuestra animación funcionando correctamente:
Conclusiones
Espero que este artículo os haya servido para profundizar tanto en las dos librerías en las que se basa: React Router y React Transition Group y que os resulte fácil a partir de ahora darle algo de “vida” a las transiciones entre las distintas rutas de vuestra aplicación.
Si queréis seguir profundizando sobre este tema os dejo un par de artículos para complementar todo lo que yo os he contado.
¿Quieres recibir más artículos como este?
Si te ha gustado este artículo te animo a que te suscribas a la newsletter que envío cada domingo con publicaciones similares a esta y más contenido recomendado: 👇👇👇