Step by step guide of simple routing transition effect for React — with react-router v4 and react-transition-group v2

Hyeokwoo Alex Kwon
8 min readMar 11, 2018

--

Page routing in React is necessary for the well practicable website. But in SPA world, such as React, routing behaves pretty different than server-side rendered websites.

As you may well know, when a website is rendered by server side, your browser requests each page when you access different routes. The browser waits for the response and renders content. But in SPA, instead of downloading every page each time, the app just unmounts old page and renders a new page, which is a component.

Therefore, the appearance of a new page over an old page can be controlled, and any effects can be applied.

On this post, let’s find out how to apply a fading effect on page transition process with React Router v4 and React Transition Group v2.

Here is a demo that we are going to build by going through steps below.

Page Transition with fading effect

Libraries to use

1. React Router v4
2. React Transition Group v2

React Router v4

React Router is the most popular and widely used routing library for React application. It’s de facto the most popular library for routing.

Static routing vs. Dynamic routing

There are some concepts to know about routing in React Router. Former versions before React Router v4, it was following so-called “static routing” method. But in v4, it now complies with “dynamic routing” method.

The critical difference between those methods is that in static routing, every routing rules are declared as soon as the app is initialized. On the other hand, in dynamic routing, the routing rules are declared where the rendering is happening, as if you are rendering component in a specific position.

Since you can declare routing rules locally with dynamic routing method, you can specify transition effect where you only want it to be happening.

API’s we are going to use

We are going to use <BrowserRouter>, <Route>, <Switch>, <Link> and withRouter() API’s provided by React Router v4. Let’s take a brief look at those API’s for composing routing on React app. If you are already familiar with these, you can just skip this part.

<BrowserRouter>

An extended component of <Router>, which is a low-level interface for other router components. The <BrowserRouter> is a component which implemented HTML5 history API on the <Router>.

<Route>

A <Route> renders component you passed in as props if the route matches. Simply put, if you set a path and a component to be rendered on <Router>, if the website’s location matches the path you set, it renders the designated component.

<Switch>

A component which can wrap multiple <Route> components and renders only single <Route>, which matches the current path.

As the component would be different based on the path, but the rendered position will always be the same. Therefore, we can apply routing transition effect by taking advantage of this feature.

<Link>

The <Link> component allows you to navigate between pages without reloading the whole app. We are going to use this for navigation header.

withRouter()

Any component rendered by <Route> has access to location, history, match as a props.

But if a component was not rendered by <Route>, you can wrap the component with withRouter() higher order component. Then you can access those prop values.

React Transition Group v2

If you try to apply transition effect on page routing, you can separate transition process into several states. But managing those states can be unwieldy. Instead, we can use React Transition Group v2 which provides terrific API’s that handles transition effect.

Steps for transition

Let’s say there is a page that is already rendered. When a user changes the location, the current page, which is a component, should disappear and the new page component will be rendered.

The steps for rendering new page component with fading effect would be like this:
1. Renders the new component
2. Setting the component’s opacity to 0
3. Change the opacity from 0 to 1 over the time

While the new component is going through those steps, the current component has to disappear:
1. Set the component’s opacity to 1
2. Change the opacity from 1 to 0 over the time
3. Remove the component

So, each component goes through an ‘enter’ and ‘exit’ process over the time to achieve a transition effect. We can easily manage those processes with components provided by React Transition Group.

Components by React Transition Group

We can achieve the ‘enter’ and ‘exit’ process of components with <CSSTransition> and <TransitionGroup> components.

<CSSTransition>

The <Transition> component of React Transition Group allows describing transition from one component to another over time.

<CSSTransition> component is a predefined <Transition> component that is using CSS transition. It applies a className on each stage of the transition.

For example, if you defined classNames props as ‘fade’, the classNames such as ‘fade-enter’, ‘fade-enter-active’, ‘fade-exit’, ‘fade-exit-active’ to the changing components. Let’s take a detailed example on next section.

<TransitionGroup>

Every <Transition> component has to be wrapped in <TransitionGroup> component which can contain multiple <Transition> components.

Building the simple page transition app

Well, now we know which libraries and API’s to use for implementing fading effect on routing transition, let’s build a simple website with the effect. We are going to use create-react-app for our project boilerplate.

Constructing components

The base application component will be <App>. It is going to include <Header> for navigation and <Container> section to contain page components.

We are going to make four pages,<Home>,<First>,<Second> and <Third>, with different contents each. I know it’s a tedious name, but let’s compensate for simplicity of explanation.

Step 1. Compose <App> for routing function

In our index.js file, the <App> component already exists. To implement routing function, import <BrowserRouter> from react-router-dom and render the component inside the <App>.

index.js

We rendered <Router> as an alias of <BrowserRouter> for simplicity. Later, we are going to render the actual contents under the <Router> component.

Step 2. Create <Header> for navigation UI

Next, let’s create <Header> component to navigate through pages.

Header.js

We created simple navigational links on header UI. By clicking anchor tags created by <Link> component, you can navigate through your app without reloading the page.

[Note] The styling library that I used here is styled-components, which allows you to style JSX element without using classes or ids. You create JSX element component with styling rules. The <Wrapper> is just a <div> with those styling rules. Check out more about styled-components. It doesn’t matter if you use other methods to style your component.

Step 3. Create <Container> and declare routes

Now, create <Container> component and construct Routing rules.

Container.js

The <Container> is holding routing rules for our app. We imported <Switch> and <Route> to construct routing rules.

Inside the <Switch>, there are four <Route> components. Each <Route> is declared of its respective path and component to render.

Since we wrapped <Route> components with <Switch>, the <Switch> component will iterate over its children, in this case, the <Route> components, and return the first one that matches the current path. Thus, only one component that matches routing rule is going to be rendered at the position where the <Switch> is rendered.

For now, as we didn’t make any components to render for each <Route> component, we passed simple rendering function to component props as () => <div>homepage</div>. We are going to replace them later.

Step 4. Import <Header> and <Container> in <App> component

As we created <Header> and <Container>, let’s render them in our main <App> component.

index.js

Since <Router> only expect to receive a single child element, we wrapped those components with <div>.

So far, you have successfully created a navigable header and implemented routing function on your app. You should be able to verify that routing works well by changing the paths.

Step 5. Create pages for each route

Now, we have well working routable app. Let’s write some example contents for each page.

Write some welcome message on our <Home>.

Home.js

Then a dummy Lorem Ipsum for <First>, <Second>, <Third>.

First.js
Second.js
Third.js

After you’ve done writing page components, let’s apply pages in our <Container> component’s <Route>.

Container.js

Step 6. Apply transition components

Finally, our routing is ready. Let’s add fading transition effect in earnest.

Import <TransitionGroup>,<CSSTransition> from react-transition-group and wrap <Switch> component as follows.

Also import withRouter() higher order component from react-router-dom, then wrap up the <Container> component.

Container.js

We wrapped <Switch> with <CSSTransition> component and wrapping it again with <TransitionGroup>.

Next, by wrapping <Container> component with withRouter(), we can access location props by react-router, which contains the information of current location.

We have to pass location.key value to <CSSTransition> as key props to trigger component transition. The key value is a unique string that represents the current location.

Then, pass location object to <Switch> to control the component to use the same location object that the transition effect is dependent on.

You can also pass transition options to <CSSTransition> as props. In this example, we set timeout delay for 300ms both for entering and exiting timespan.

Step 7. Define CSS styling rules for transition

To apply actual transition effect, we have to declare transition rules with CSS. Let’s add ‘fade’ as value for classNames prop on <CSSTransition> component.

Container.js

Do you remember that when the transition happens, the components go through ‘enter’ and ‘exit’ processes? When you declare ‘fade’ as classNames prop, ‘fade-enter’, ‘fade-enter-active’, ‘fade-exit’, ‘fade-exit-active’ classes will be applied.

Therefore, we can declare transition effects for each class like this:

fade.css

Let’s apply this CSS rule on our <Container> component!

Container.js

In our <Wrapper>(<div> element), we applied those CSS rules, and the transition is working now.

Wait, but this is not what we expected…!

Step 8. Additional styling for seamless fade-in and out

For now, during the transition time(300ms), those two components are rendered simultaneously.

The current one is at the same position where it was positioned, and it’s on fading out process. At the same time, a new component is rendered just below the current one. Not at the same position where the current component is rendered.

This transition behavior is not what we expected. We want those two components to fade in and out at the same position.

How do we achieve this? We can do it by tricking CSS styling.

First, wrap the <Switch> component with new <section> component. And add styling rules for both <TransitionGroup> and <section> components.

Container.js

To make both components to be rendered at the same position, we set the <section>’s position to be absolute against <TransitionGroup>. We set .route-section className for <section> , and .transition-group for <TransitionGroup> and wrote those styling rules in <Wrapper> component. Now we have seamless fading effect for page transition.

That’s it! We have successfully created sample app with fading effect on routing pages. Congrats!

Wrapping up

I’ve had a little trouble when I was trying to implement transition effect for page routing. Because most of the articles about routing transitions were based on former version of React Transition Group. That’s why I decided to write a new article about the topic.

You can achieve this sort of effect by using a library like react-router-transition. But instead, if you just need a simple transition effect, using React Transition Group would be sufficient.

Thanks for reading, and please share this article someone who might need it!😝

--

--