react-router-page-transition
Version:
Highly customizable page transition component for your your React Router
354 lines (300 loc) • 8.22 kB
Markdown
# Examples
## Example 1: Simple sliding trasition

This is a simple transition: detail page slide in from the right.
### Router
```js
ReactDOM.render(
<Router history={hashHistory}>
<Route path="/" component={Home}>
<IndexRoute component={ListPage} />
<Route path="/detail/:itemId" component={DetailPage} />
</Route>
</Router>, document.getElementById('app'));
```
### ListPage component
```js
export default class ListPage extends React.Component {
...
render() {
return (
<div className="transition-item list-page">
{this.state.items.map(item => (
<Link
key={item.id}
className="list-item"
to={`/detail/${item.id}`}
>
<Item {...item} />
</Link>
))}
</div>
);
}
```
### Home component
```js
import React from 'react';
import ReactDom from 'react-dom';
import PageTransition from 'react-router-page-transition';
export default (props) => (
<div>
<PageTransition>
{props.children}
</PageTransition>
</div>
);
```
### DetailPage component
Add class `transition-item` to your root element, we will use this to animate the page
when route change.
```jsx
export default class DetailPage extends React.Component {
render() {
return (
<div className="transition-item detail-page">
<Link to="/">Back</Link>
<h1>
Detail {this.props.params.itemId}
</h1>
</div>
);
}
}
```
### CSS:
Define animation using CSS
```less
.transition-wrapper {
position: relative;
z-index: 1;
.transition-item {
position: fixed;
top: 0;
right: 0;
left: 0;
}
}
.detail-page {
overflow: auto;
box-sizing: border-box;
padding: 20px;
height: 100vh;
background-color: #03a9f4;
transition: transform 0.5s, opacity 0.5s;
&.transition-appear {
opacity: 0;
transform: translate3d(100%, 0, 0);
}
&.transition-appear.transition-appear-active {
opacity: 1;
transform: translate3d(0, 0, 0);
}
&.transition-leave {
opacity: 1;
transform: translate3d(0, 0, 0);
}
&.transition-leave.transition-leave-active {
opacity: 0;
transform: translate3d(100%, 0, 0);
}
}
.list-page {
overflow: auto;
box-sizing: border-box;
padding: 20px;
height: 100vh;
background-color: #fff;
transition: transform 0.5s, opacity 0.5s;
transform: translate3d(0, 0, 0);
&.transition-appear {
opacity: 0;
transform: translate3d(-100%, 0, 0);
}
&.transition-appear.transition-appear-active {
opacity: 1;
transform: translate3d(0, 0, 0);
}
&.transition-leave {
opacity: 1;
transform: translate3d(0, 0, 0);
}
&.transition-leave.transition-leave-active {
opacity: 0;
transform: translate3d(-100%, 0, 0);
}
}
```
**See demo:** https://trungdq88.github.io/react-router-page-transition/simple/
## Example 2: Material design transition
From a cool idea of [Material Motion](https://material.google.com/motion/material-motion.html#material-motion-how-does-material-move) that provide meaningful transition between pages.


In order to implement this, we need to pass custom data into the detail page, which requires a data flow management for the app. In this example, I'll use **RxJS** to pass data between ListPage component, Home component and ItemDetalPage component, but you can use another library to handle the data (like Flux or Redux).
### ListPage component
See the `onClick` method, we send the clicked item's data (color and position) to the action.
```js
render() {
return (
<div className="transition-item list-page">
{this.state.items.map(item => (
<Link
key={item.id}
className="list-item"
onClick={e => action.onNext({
name: 'CLICKED_ITEM_DATA',
data: {
position: e.target.getBoundingClientRect(),
color: item.color,
},
})}
to={`/detail/${item.id}`}
>
<Item {...item} />
</Link>
))}
</div>
);
}
```
### Home component
Home component receives the data and pass it to the `PageTransition` component.
```js
export default class Home extends React.Component {
constructor(...args) {
super(...args);
this.state = {
clickedItemData: null,
};
}
componentDidMount() {
// Receive data from the clicked item
this.obsClickedItemData = action
.filter(a => a.name === 'CLICKED_ITEM_DATA')
.map(a => a.data)
.subscribe(clickedItemData => this.setState({ clickedItemData }));
}
componentWillUnmount() {
this.obsClickedItemData.dispose();
}
render() {
return (
<div>
<PageTransition
data={{ clickedItemData: this.state.clickedItemData }}
>
{this.props.children}
</PageTransition>
</div>
);
}
}
```
### DetailPage component
This component will receive the callbacks with data from `PageTransition` component, then we can use tihs to animate our page as we want.
```js
export default class DetailPage extends React.Component {
constructor(...args) {
super(...args);
this.state = {
doTransform: false,
position: null,
color: null,
};
}
onTransitionWillStart(data) {
// Start position of the page
this.setState({
doTransform: true,
position: data.clickedItemData.position,
color: data.clickedItemData.color,
});
}
onTransitionDidEnd() {
// Transition is done, do your stuff here
}
transitionManuallyStart() {
// When this method exsits, `transition-appear-active` will not be added to the dom
// we will define our animation manually.
this.setState({
position: {
top: 0,
height: '100%',
left: 0,
right: 0,
},
doTransform: true,
});
}
transitionManuallyStop() {
// When this method exsits, `transition-appear-active` will not be removed
this.setState({
doTransform: false,
});
}
render() {
return (
<div
style={{
transform: this.state.doTransform ?
`translate3d(0, ${this.state.position.top}px, 0)` :
undefined,
height: this.state.doTransform ?
this.state.position.height : null,
left: this.state.doTransform ?
this.state.position.left : null,
right: this.state.doTransform ?
this.state.position.left : null,
backgroundColor: this.state.color,
}}
className="transition-item detail-page"
>
<Link to="/">
Item {this.props.params.itemId}
</Link>
<h1>
Detail page here
</h1>
<Link to="/">
Back
</Link>
</div>
);
}
```
### CSS
```css
.transition-wrapper {
position: relative;
z-index: 1;
.transition-item {
position: fixed;
top: 0;
left: 0;
right: 0;
}
}
.detail-page {
padding: 10px 10px;
background-color: #03a9f4;
height: 100vh;
box-sizing: border-box;
overflow: hidden;
a {
color: white;
}
&.transition-appear {
transition: transform 1s cubic-bezier(0.7, 0, 0.25, 1),
left 1s cubic-bezier(0.7, 0, 0.25, 1),
right 1s cubic-bezier(0.7, 0, 0.25, 1),
height 1s cubic-bezier(0.7, 0, 0.25, 1);
}
&.transition-appear.transition-appear-active {
}
}
```
**See demo:** https://trungdq88.github.io/react-router-page-transition/material/
## Example 3: Reveal effect

Similar to the material example, we use `border-radius` to animate the circle.
**See demo:** https://trungdq88.github.io/react-router-page-transition/reveal/