Skip to content
A component for manage animated routes transitions in React.
Branch: develop
Clone or download

Latest commit

Fetching latest commit…
Cannot retrieve the latest commit at this time.


Type Name Latest commit message Commit time
Failed to load latest commit information.


A component for manage animated route transitions with React, built with React Router and xstate.

How it works

Basically, this component is responsible to invoke lifecycles from the passed component.
On first landing, this are the invoked lifecycles:

  1. componentWillAppear (async)
  2. componentDidAppear (sync)

On all the next transition:

  1. preload (async, optional)
    If component is a dynamic component (see @loadable/component), preload method will be invoked
  2. fetchData (async, optional)
    If exposed, component.fetchData will be invoked (useful in SSR environments for fetch external data)
  3. componentWillLeave (async)
  4. componentDidLeave (sync)
  5. componentWillEnter (async)
  6. componentDidEnter (sync)

See here the related xstate machine.

Props table

Param Type Default Description
parallel Boolean false If set to true, leave and enter are called simultaneally
dispatch Function () => {} Store dispatch function, used internally for manage reducer and fetchData method


1st: replace Switch with AnimatedSwitch

import AnimatedSwitch from 'react-router-animation-switch';
import { useDispatch } from 'react-redux';
import { Route } from 'react-router-dom';

export default () => {
  const dispatch = useDispatch();

  return (
    <AnimatedSwitch dispatch={dispatch}>
      <Route path="foo" component={Foo} />
      <Route path="bar" component={Bar} />

2st: expose lifecycles from each Route component

import React, { forwardRef, useRef, useImperativeHandle } from 'react';
import anime from 'animejs';

const Foo = forwardRef((props, ref) => {
  const $wrapperRef = useRef();

  const enterAnimation = () => anime({
    targets: $wrapperRef.current,
    opacity: [0, 1],
    easing: 'linear',

  const leaveAnimation = () => anime({
    targets: $wrapperRef.current,
    opacity: 0,
    easing: 'linear',

  useImperativeHandle(ref => ({
    componentWillAppear: enterAnimation,
    componentWillEnter: enterAnimation,
    componentWillLeave: leaveAnimation,
    componentDidAppear: () => console.log('Appeared'),
    componentDidEnter: () => console.log('Entered'),
    componentDidLeave: () => console.log('Leaved'),

  return () => <div ref={$wrapperRef}>Foo example component</div>;

Foo.fetchData = async ({ dispatch, match }) => {
  // fetch data from external resource

export default Foo;

3th: connect reducer (optional)

import { reducer } from 'react-router-animation-switch';

export default combineReducers({
  pageTransition: reducer,

Reducer structure

Param Type Default Description
pageTransition.isActive Boolean false If true, a page transition is in progress
* Example usage
* Reset scrollTop when transition is finished
useEffect(() => {
  if (!isActive) {
    document.documentElement.scrollTop = 0;
}, [isActive])
You can’t perform that action at this time.