React Router v4 with React-Transition-Group v2

Example tutorial of using React Router 4 (react-router-dom) and react transition group v2 (TransitionGroup and CSSTransition)

Victor Leong
4 min readSep 24, 2017

I’ve been looking for tutorials and documentation about using the latest react-router 4 (react-router-dom to be specific) and react-transition-group v2 (TransitionGroup and CSSTransition). However, most of them are outdated and the codes do not really work.

So here’s my version of it.

Requirements

The versions that are used here are:

Project

Here’s the main gist of this project:

Able to navigate to a page from the home page and back, showing fade animations in the process.

There will be 3 main components.

  • App — the mother component of the app. It will handle the routing.
  • Home — show the home page when the path is exactly /
  • Content — show the page when the path is /:contentId where contentId can be anything

This repository of this project is located here.

The Mother Component

First, the code.

In case you do not recognise the jsx here, I am using haml jsx. It basically uses indents to close up html element tags instead of having you write them.

It originates from HAML which is commonly used in Rails projects. It has been a great time saver for my Rails projects (although I prefer its, literally, slimmer counterpart). This library is still a bit quirky but I hope it gets popular and better in time.

const App = () => {
return (~
%main.grid-container
.grid-x.grid-margin-x
%TransitionGroup
%Switch
%Route(
path="/:contentId"
component={Content})
%Route(
path="/"
exact=""
component={Home})
~)
}

Things to note:

  • All CSSTransition components need to be wrapped inside a TransitionGroup in order for the animation to occur between different urls.
  • A TransitionGroup component only accepts CSSTransition components as its children. The Switch component will qualify if the components Home and Content returns CSSTransition components, which they will. Try adding a <section> element as a sibling to the Switch component and you will see errors in your browser console.

The Main Components

The most important point of using react-transition-group is the in props that is passed to the CSSTransition component.

For this project, each of them will have a state to store the value of in with a default value of true Then, they will use the lifecycle method componentWillUnmount to detect a change in route and thus an unmount event, thereby falsifying the value of in.

constructor(props) {
super(props)
this.state = { in: true }
}
componentWillUnmount() {
this.setState({in: false})
}

As mentioned, these components will need to return CSSTransition component as they are wrapped in a TransitionGroup component that only accepts CSSTransition component as children.

We will use a Higher-Order Component (HOC) as the root element in these components. This HOC will be returning the CSSTransition.

The HOC

First, the code.

const FadeTransition = ({shouldShow, timeout, classNames, children}) => {
return (
<CSSTransition
timeout={timeout}
classNames={classNames}
in={shouldShow}>
{children} </CSSTransition>
)
}

Thing to note:

  • timeout, classNames and in are required props by the CSSTransition component
  • the shouldShow keyword is used instead of in because in is a reserved keyword. This got me itching quite a bit. I am betting that the community will be changing the name in soon
  • Although the prop children signifies plural, take note that only 1 child component is accepted in a CSSTransition component.

Back to the Main Components

First, the code of the render functions.

// Content.jsrender() {
return (~
%FadeTransition(
timeout={350}
classNames="fade"
shouldShow={this.state.in})
.cell.text-center
%h1 This is {params.contentId} page !!

%Link(to="/") Back
~)
// Home.jsrender() {
return (~
%FadeTransition(
timeout={350}
classNames="fade"
shouldShow={this.state.in})

%div
%h1 This is HOME page
%br
{this.renderLinks()}
~)
}
renderLinks = () => {
return [
"Luffy",
"Zoro",
"Nami",
"Usopp",
"Sanji",
"Chopper",
"Nico Robin",
"Franky",
"Brooke",
].map(character => {
return (~
%Link(
key={character}
to={`/${character.toLowerCase()}`})
Visit {character} now!
%br
~)
})
}

Things to note:

The CSS

Copied from here, just sass-ified it.

.fade-enter
opacity: 0.01
.fade-enter.fade-enter-active
opacity: 1
transition: opacity 500ms ease-in
.fade-exit
opacity: 1
.fade-exit.fade-exit-active
opacity: 0.01
transition: opacity 300ms ease-in

Results

You should be able to see the Home and Content pages fade in and out when you click the links to navigate the site.

Clicking the back button in the Chrome browser also will also trigger the animations.

Conclusion

The most important thing to note is the in props supplied to each CSSTransition component. At least it is for me, imho, from the various failed attempts at the 2 libraries. Hope it was helpful!

--

--