Skip to content
This repository has been archived by the owner on Nov 18, 2020. It is now read-only.

Latest commit

 

History

History
353 lines (300 loc) · 8.03 KB

EXAMPLES.md

File metadata and controls

353 lines (300 loc) · 8.03 KB

Examples

Example 1: Simple sliding trasition

rrpt-leave

This is a simple transition: detail page slide in from the right.

Router

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

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

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.

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

.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 that provide meaningful transition between pages.

material-sample

material

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.

  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.

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.

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

.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

reveal

Similar to the material example, we use border-radius to animate the circle.

See demo: https://trungdq88.github.io/react-router-page-transition/reveal/