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)
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:
- react-router-dom: ^4.2.2
- react-transition-group: ^2.2.0
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
wherecontentId
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 aTransitionGroup
in order for the animation to occur between different urls. - A
TransitionGroup
component only acceptsCSSTransition
components as its children. TheSwitch
component will qualify if the componentsHome
andContent
returnsCSSTransition
components, which they will. Try adding a<section>
element as a sibling to theSwitch
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
andin
are required props by the CSSTransition component- the
shouldShow
keyword is used instead ofin
becausein
is a reserved keyword. This got me itching quite a bit. I am betting that the community will be changing the namein
soon - Although the prop
children
signifies plural, take note that only 1 child component is accepted in aCSSTransition
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:
- Yes, I’m a One Piece fan :).
- The value of
classNames
props will give thecss
classesfade-enter
,fade-enter-active
,fade-exit
,fade-exit-active
etc. meaning. - Just to emphasise again, there should only be1 child component in the
CSSTransition
component
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!