React-router: Different animations for page transition

Created on 20 May 2015  路  18Comments  路  Source: ReactTraining/react-router

I have seen the animations example Link to animations. My use case is something like this. I want a transition when routing form a component to another(say slide right), and need an opposite transition when clicking back button of browser(say slide left) or a custom back button I have created. I am trying to implement a transition like ion-nav-view,See this. This demo of ionic works even when I click the browser back button or its UI back button. I would like to implement similer thing in react with excat animations. How should I do it with react-router?

Most helpful comment

hi, it is a right way to handle diffrent animation ?

I set index prop on <Route />

  <Provider store={store}>
    <Router history={history}>
      <Route path="/" component={App}>
        <IndexRoute index="0" component={HomePage} />
        <Route path="usercenter">
          <IndexRoute index="1" component={UserCenter} />
          <Route index="2" path="changepassword" component={ChangePassword} />
          <Route index="2" path="feedback" component={FeedBack} />
        </Route>
        <Route index="2" path="applydiscount" component={ApplyDiscount} />
        <Route index="1" path="businesstracking" component={BusinessTracking} />
        <Route index="1" path="priceview" component={PriceView} />
        <Route index="1" path="calculator" component={Calculator} />
        <Route index="10" path="*" component={Bar} />
      </Route>
    </Router>
  </Provider>
import React, { Component } from 'react'
import { Container } from 'amazeui-touch'
import './styles.styl'
class App extends Component {
  constructor(props) {
    super(props)
    this.state = {
      transition: 'sfr'
    }
  }
  componentWillReceiveProps(nextProps) {
    const thisIndex = this.props.children.props.route.index
    const nextIndex = nextProps.children.props.route.index
    const transition = nextIndex - thisIndex > 0 ? 'sfr' : 'rfr'
    this.setState({ transition })
  }
  render() {
    const { transition } = this.state
    const { location: { pathname } } = this.props
    return (
      <Container transition={transition}>
        {React.cloneElement(this.props.children, { key: pathname })}
      </Container>
    )
  }
}

export default App

All 18 comments

+1 for example showing how to do this, currently attempting to do pretty much the exact same thing

One react example I've found is pageslider-react (GitHub, demo Edit: Seems to work only in Chrome). An example implementation of this using react-router would be very helpful, but I'm unsure about the best way to approach this using the current react-router animation api.

http://coenraets.org/blog/2014/12/animated-page-transitions-with-react-js/ not works with firefox. re-app kit has similer item (Nested view), but when using reapp-ui alone it breaks. We can use CSSTransistiongroup with transistionappear={true} to get appear transition on routing. But when routing back to the url still remains problem

I have seen a property in CSStransition group transitionappear = [true} . helps to get transition when routes to new component. I wonder if something like transitionleave is not there?

This is how I hacked my way through this problem:

render() {
    const path = this.context.router.getCurrentPath();
    const segment = path.split('/')[1] || 'root';

    return (
        <TransitionGroup component='div' transitionName={segment === 'root' ? 'reversePageSwap' : 'pageSwap'}>
            <RouteHandler key={segment}/>
        </TransitionGroup>
    );
}

This is quite brittle if you want more control over which animation is running for a given transition between two routes, but it did the job for my specific use case of homepage -> subpages and subpages -> homepage transitions (never subpage -> subpage). To go further I'd probably have a look at using the nextProps in componentWillReceiveProps as described in those issues: https://github.com/rackt/react-router/issues/681, https://github.com/rackt/react-router/issues/698.

Sidenote: I think this would definitely deserve a reference implementation linked from react-router's documentation, either in the examples or from an OSS project implementing that particular pattern.

I have a homepage -> subpage -> subpage transition and back. It has been implemented with ionic pretty well. not with react

I'm glad you asked about this @abhilashsajeev :)

In the 1.0 API (try npm install [email protected]) we introduced a <Link state> property. You could feasibly use this property to pass along animation instructions to the component that uses <TransitionGroup>, but we're also working on a better API specifically for animations, so let's leave this open for now.

@mjackson That will be nice. I am looking forward to it. This page transition animation is the major chaos we encountered converting an ionic webapp to react.

using props.children and the location.state features, I think we have what we need to do great animations now. hopefully we'll have an example soon.

Any update, examples, or guides on this? I get what is said above about the link.state to determine which direction to go, but I am still unclear on how to animate the entire page for slideLeft/slideRight-type page transitions.

Thanks!

Take a look at the animation examples.

Thank you. I had seen that in the demo, but since it wasn't a full-page example, I didn't realize it was what I wanted. I looked at it more closely and it's spot on.

I just wrote a very simple module "react-easy-transition" to do CSS transitions on route change. You can see the demo working with react-router 2.0. To use it just do

<EasyTransition 
    path={location.pathname}
    initialStyle={{opacity: 0}}
    transition="opacity 0.3s ease-in"
    finalStyle={{opacity: 1}}
>
    {this.props.children}
</EasyTransition>

I do not see anywhere in the animations examples where we manage different transitionName values based on the Router/history behavio (back or next)... @hellogerard Have you found something?

@zabojad

There is no exact example. But you can adapt the one in examples/animations. In that app, the ReactCSSTransitionGroup has a prop called transitionName. That's what you have to control. For example, you might have to set it to 'slideLeft' to go into a subpage. And then from the subpage, set it to 'slideRight' to go back.

If you create a link like: <Link to="/where-ever" state={{transition: 'slideLeft'}}></Link>

You can then access it in your main route component's context: this.context.location.state. For example:

  <ReactCSSTransitionGroup transitionName={{this.context.location.state}} ... > ... </ReactCSSTransitionGroup>

For those that find this discussion, a change I encountered with implementing this was that the state prop was deprecated in favor of <Link to> accepting a location descriptor.

<Link to={{ pathname: '/path-to-screen', state: { transition: 'slideDown' }}>
  Click Me!
</Link>

Hope it helps.

hi, it is a right way to handle diffrent animation ?

I set index prop on <Route />

  <Provider store={store}>
    <Router history={history}>
      <Route path="/" component={App}>
        <IndexRoute index="0" component={HomePage} />
        <Route path="usercenter">
          <IndexRoute index="1" component={UserCenter} />
          <Route index="2" path="changepassword" component={ChangePassword} />
          <Route index="2" path="feedback" component={FeedBack} />
        </Route>
        <Route index="2" path="applydiscount" component={ApplyDiscount} />
        <Route index="1" path="businesstracking" component={BusinessTracking} />
        <Route index="1" path="priceview" component={PriceView} />
        <Route index="1" path="calculator" component={Calculator} />
        <Route index="10" path="*" component={Bar} />
      </Route>
    </Router>
  </Provider>
import React, { Component } from 'react'
import { Container } from 'amazeui-touch'
import './styles.styl'
class App extends Component {
  constructor(props) {
    super(props)
    this.state = {
      transition: 'sfr'
    }
  }
  componentWillReceiveProps(nextProps) {
    const thisIndex = this.props.children.props.route.index
    const nextIndex = nextProps.children.props.route.index
    const transition = nextIndex - thisIndex > 0 ? 'sfr' : 'rfr'
    this.setState({ transition })
  }
  render() {
    const { transition } = this.state
    const { location: { pathname } } = this.props
    return (
      <Container transition={transition}>
        {React.cloneElement(this.props.children, { key: pathname })}
      </Container>
    )
  }
}

export default App

Got this working, you need two different animation classes, one for animation out and another for animating in, then do this:

<ReactCSSTransitionGroup
    transitionName={this.props.location.action === "PUSH" ? "animate-in" : "animate-out"}
    transitionEnterTimeout={600}
    transitionLeaveTimeout={600}
>
{React.cloneElement(this.props.children, { key: segment })}
</ReactCSSTransitionGroup>
Was this page helpful?
0 / 5 - 0 ratings

Related issues

ackvf picture ackvf  路  3Comments

yormi picture yormi  路  3Comments

hgezim picture hgezim  路  3Comments

andrewpillar picture andrewpillar  路  3Comments

alexyaseen picture alexyaseen  路  3Comments