Skip to main content

Lab 21 a: Route Transitions

This lab is optional and should only be done if time permits

Objectives

  • Animate in and out pages as routes transition

Steps

  1. Install the react-transition-group library.

    React Transition Group exposes simple components useful for defining entering and exiting transitions.

    React Transition Group used to be part of the React library itself but has since been removed and is part of ReactCommunity.org.

    # npm
    npm install react-transition-group

    # if using TypeScript
    npm install @types/react-transition-group

    # yarn
    yarn add react-transition-group
  2. Move the <Router> component up one level to wrap the entire App. This is necessary for us to be able to access the new useLocation hook that is part of react-router at the point we use the CSSTransition and Routes components. We get the location using the useLocation hook.

    You can't use any of the hooks from within the same component that puts the Router into the tree. You need to move your BrowserRouter out of that component. It can go in the root.render() call, for instance.

    React Transition Group is not an animation library like React-Motion, it does not animate styles by itself. Instead it exposes transition stages, manages classes and group elements and manipulates the DOM in useful ways, making the implementation of actual visual transitions much easier.

    src\App.js

    ...
    import {
    - BrowserRouter as Router,
    Route,
    NavLink,
    Routes,
    + useLocation,
    } from 'react-router-dom';

    ...

    function App() {
    + let location = useLocation();
    return (
    <Provider store={store}>
    - <Router>
    <header className="sticky">
    <span className="logo">
    <img src="/assets/logo-3.svg" alt="logo" width="49" height="99" />
    </span>
    <NavLink to="/" className="button rounded">
    <span className="icon-home"></span>
    Home
    </NavLink>
    <NavLink to="/projects/" className="button rounded">
    Projects
    </NavLink>
    </header>
    <div className="container">
    <Routes location={location}>
    <Route path="/" component={HomePage} />
    <Route path="/projects" component={ProjectsPage} />
    <Route path="/projects/:id" component={ProjectPage} />
    </Routes>
    </div>
    - </Router>
    </Provider>
    );
    }

    export default App;

    src\index.js

    ...
    + import { BrowserRouter as Router } from 'react-router-dom';

    const root = ReactDOM.createRoot(document.getElementById('root'));
    root.render(
    <React.StrictMode>
    + <Router>
    <App />
    + </Router>
    </React.StrictMode>
    );

  3. Wrap the react-router's Routes component with a TransitionGroup and CSSTransition component from the react-transition-group library.

    src\App.js

    + import { CSSTransition, TransitionGroup } from 'react-transition-group';

    function App() {
    let location = useLocation();
    return (
    <Provider store={store}>
    <header className="sticky">
    <span className="logo">
    <img src="/assets/logo-3.svg" alt="logo" width="49" height="99" />
    </span>
    <NavLink to="/" className="button rounded">
    <span className="icon-home"></span>
    Home
    </NavLink>
    <NavLink to="/projects/" className="button rounded">
    Projects
    </NavLink>
    </header>
    <div className="container">
    + <TransitionGroup>
    + <CSSTransition key={location.key} classNames="fade" timeout={{ enter: 400, exit: 200 }}>
    - <Routes>
    + <Routes location={location}>
    <Route path="/" component={HomePage} />
    <Route path="/projects" component={ProjectsPage} />
    <Route path="/projects/:id" component={ProjectPage} />
    </Routes>
    + </CSSTransition>
    + </TransitionGroup>
    </div>
    </Provider>
    );
    }

    export default App;
  1. Add the page and fade CSS styles.

    src\index.css
    ... 
    /* add these below existing styles */

    .fade-enter {
    opacity: 0;
    z-index: 1;
    }

    .fade-enter.fade-enter-active {
    opacity: 1;
    transition: opacity 400ms ease-in;
    }

    .fade-exit.fade-exit-active {
    opacity: 1;
    transition: opacity 200ms ease-in;
    }

    This style should already exist but it is also important to ensure your container has a height of 100 percent.

    .container {
    height: 100%;
    }
  2. Click through the pages in the application and see the previous page content fade out and the new page content fade in to view.

Libraries Compared

React Transition Group just makes transitions easier. It is not an animation library. React Spring and React Framer Motion are animation libraries. Historically, React Spring has been the most popular library but React Framer Motion was released more recently and tends to be easier to use and comprehend. This article can be useful in making a decision on a library: What’s the most developer-friendly React animation library?.

Reference