Comments (43)
If like me you're just trying to get simple CSS transitions to work (especially fade-out) with react-router 2.0, and you don't need the heavy artillery, you can use "react-easy-transition", a very lightweight module that I wrote to solve that.
<EasyTransition
path={location.pathname}
initialStyle={{opacity: 0}}
transition="opacity 0.3s ease-in"
finalStyle={{opacity: 1}}
>
{this.props.children}
</EasyTransition>
The demo with redux integration
from react-router.
Check out the oficial example. There are alternatives to react-addons-css-transition-group such as velocity-react and react-motion.
Here's a simple example of a RouteTransition
component, that will animate all it's children:
import React from 'react';
import {TransitionMotion, spring} from 'react-motion';
const willEnter = children => ({children, opacity: spring(0), translate: spring(999)});
const willLeave = (key, {children}) => ({children, opacity: spring(0), translate: spring(-999)});
const getStyles = (children, pathname) => ({[pathname]: {children, opacity: spring(1), translate: spring(0)}});
export default function RouteTransition({children, pathname}) {
return (
<TransitionMotion
styles={getStyles(children, pathname)}
willEnter={willEnter}
willLeave={willLeave}
>
{interpolated =>
<div>
{Object.keys(interpolated).map(key =>
<div
key={`${key}-transition`}
style={{
height: '100%',
width: '100%',
position: 'absolute',
opacity: interpolated[key].opacity,
transform: `translateX(${interpolated[key].translate}px)`
}}
>
{interpolated[key].children}
</div>
)}
</div>
}
</TransitionMotion>
);
}
Simply wrap and it's done:
<RouteTransition pathname={this.props.location.pathname} style={{visibility: 'hidden', width: '100%', height: '100%'}}>
{this.props.children}
</RouteTransition>
from react-router.
None of these examples work with asynchronous routing, has anyone got any examples of that?
Looking for something that starts fading out before the next chunk has loaded.
from react-router.
Has anyone been able to crossfade with React Router? Every example I've seen will not fade in the new route until the old route is fully faded out, which flashes the screen in a jarring way. Looking for a crossfade solution!
from react-router.
I managed it in the end. Although for my use case I had a swiping transition. Things I learnt:
- Don't use
ReactTransitionGroup
orReactCSSTransitionGroup
, these animations aren't interruptible, makes it feel clunky if the user navigates quickly. ThecomponentWillEnter
won't fire until it'scomponentWillLeave
method has finished completing if the user navigates forward and then back to the same component (means they have to wait for the fade to complete) - Avoid using the asynchronous
getComponent
in react-router, seems like this isn't interruptible. I.e. if I navigate to a new page which callsgetComponent
and then the user presses back beforegetComponent
resolves, they will end up with the wrong component loaded for the current url whengetComponent
does resolve. Didn't test this to much so could be wrong. - Side note: If you are experimenting with
ReactTransitionGroup
the lifecycle methods won't get called if you're using any sort of higher order component like react-redux's connect, which is a pretty common use case. For react-redux explicitly you can use their{withRef: true}
parameter and then usegetWrappedInstance
, although it's the only escape hatch I know, I strongly dislike it, as it seems to break my seperation of concerns between Dumb and State components.
I went with react-motion, it's the only library that seems to exist that allows you to interrupt animations, even native css animations can't do it, seems animation on the web is seriously lacking, happy to be told I'm wrong.
I have an App component that renders all the child components (pages) within it. I added some logic (using redux) that would unmount the current page when a script chunk was loading, this would give me my page swipe out animation before the next chunk has started loading.
Then my navigation code looked something like this, i.e. the user would click a 'Next' button and it would fire the below code.
dispatch({
type: 'UPDATE_SCRIPT_CHUNK_IS_LOADING',
value: true,
})
// Webpack loading of the next chunk needed to display the next page
require.ensure([], (require) => {
this.context.router.push(`Personal/Index`)
dispatch({
type: 'UPDATE_SCRIPT_CHUNK_IS_LOADING',
value: false,
})
}, "personal")
The dispatch updates my app redux state so that my App component knows to unmount it's current page. When the next chunk has loaded 'script chunk loading' is turned off in state and the next page is animated in. react-motion takes care of the animating quite elegantly, although it took me a fair bit of time figuring out how their <TransitionMotion />
api worked.
The downside to this method, is the delay the user gets between clicking to navigate and the url in the address bar changing (although the unmount animation is instant). And having to wrap navigation points in chunk loading statements. I think this is the best we can do at the moment though.
from react-router.
I created a PanelsTransition
component that would animate a panel in and out when the user navigates.
import React, { Component } from 'react'
import { TransitionMotion, spring, presets } from 'react-motion'
// These are just some convenience functions to help calculate the left position of the
// animation
import { getPanelWidth, calculatePanelToEdgeOfScreenDistance } from './../../Panel'
// The css just makes the leaving component `position:absolute` so that it doesn't
// take up space in the document
require('./PanelsTransition.css')
const calculatePosition = (x, delta) => {
// If we're not in a browser environment don't do anything
if (typeof window === 'undefined') return 0;
const dist = calculatePanelToEdgeOfScreenDistance()
return dist * x * delta
};
class PanelsTransition extends Component {
static propTypes = {
/**
* The direction of navigation, 1 for forwards, -1 for backwards
*/
delta: React.PropTypes.number,
/**
* Set this to true to animate on initial render
*/
animateOnInitialRender: React.PropTypes.bool,
};
static defaultProps = {
animateOnInitialRender: false,
};
willLeave = () => {
return {
transitionAmount: spring(-1, {stiffness: 300, damping: 26}),
finalAmount: -1,
}
};
willEnter = () => {
return {
transitionAmount: 1,
finalAmount: 1,
}
};
render = () => {
const { pathname, delta, animateOnInitialRender } = this.props
// If it isn't an initial render then animate in the first component
if (animateOnInitialRender){
var defaultStyles = [{
key: pathname,
style: {
transitionAmount: spring(1, presets.gentle),
finalAmount: 1,
},
data: {
component: this.props.children,
},
}]
}
return <TransitionMotion
willLeave={this.willLeave}
willEnter={this.willEnter}
defaultStyles={defaultStyles}
styles={[{
key: pathname,
style: {
transitionAmount: spring(0, presets.gentle),
finalAmount: 0,
},
data: {
component: this.props.children,
},
}]}>
{interpolatedStyles => {
return <div>
{interpolatedStyles.map(config => {
const isLeaving = config.style.finalAmount == -1
return <div
// Makes leaving components absolute so they don't take up space
// in the document
className={`PanelsTransition${isLeaving ? '-leaving' : ''}`}
key={config.key}
>
<div style={{
position: 'relative',
left: calculatePosition(config.style.transitionAmount, delta),
}}>
{config.data.component}
</div>
</div>
})}
</div>
}}
</TransitionMotion>
}
}
export default PanelsTransition
In my App component I then had something like this
class App extends Component {
render = () => {
const { scriptChunkIsLoading } = this.props
// I've got my routing state in redux and can figure out
// the direction of navigation there but this can come from
// anywhere or be passed in as props
const state = this.context.store.getState()
const { delta, initialRender } = state.routing
var pathname = this.props.location.pathname
// Ensure the path always starts with a slash, I've seen it be inconsistent
// sometimes
if (pathname.startsWith('/') == false)
pathname = '/' + pathname
// Make sure our child element has a key that relates to our page
// this is important
var child = React.cloneElement(this.props.children, {
key: pathname,
})
if (scriptChunkIsLoading){
// This is kind of crude, it's just means we override our child element and
// render an empty div that takes up space in the document,
// helps with the unmount animation. Only useful for me as a way of pushing
// a footer element down the screen, rendering null would work just as well
var child = <div
style={{
height: (typeof document !== 'undefined') ? document.body.clientHeight : 1280
}}
/>
pathname = "animationPlaceholder"
}
return <div>
...
<PanelsTransition
pathname={pathname}
delta={delta}
>
{child}
</PanelsTransition>
...
</div>
}
}
It doesn't work perfectly, I plan on improving it, the direction of the animation is wrong when the animation get's interrupted, but apart from that it seems to work well, the finalAmount bit is a bit of a hacky work in progress, that would likely change once I fix this up.
The react-motion api feels a bit awkward and that maybe I'm not using it the way it's intended especially with the way I've hijacked their data key to keep a reference to the component which then gets rendered, but hell it works.
from react-router.
I created a pen with a working example:
http://codepen.io/luisrudge/pen/QbEeOR
from react-router.
@iammerrick https://github.com/rackt/react-router/tree/master/examples/animations
from react-router.
The bundled animation example shows that.
from react-router.
@mjackson do you have any examples of doing this anywhere by chance?
from react-router.
@cavneb We're still working on this. I have a half-finished example, but I couldn't get it working.
from react-router.
I would also love this feature!
from react-router.
I was able to achieve this without issue with the React TransitionGroup (I'm using JS-based animations) by simply doing:
<TransitionGroup>
<this.props.activeRouteHandler />
</TransitionGroup>
from react-router.
woah ... an unexpected side-effect of #90, @jbrantly would love for you to add a demo to examples/
:D
from react-router.
This actually would have worked before #90 I think, just put {this.props.activeRoute}
inside the transition group.
from react-router.
+1 for the example mention :)
from react-router.
Sorry, I started to do this but didn't have the time to finish. Glad to see you got it done anyways!
from react-router.
Seems like wrapping <this.props.activeRouteHandler />
in <TransitionGroup>
no longer works in version 0.6.x (and 0.7.x) unless you add addHandlerKey={true}
to your Route.
Does anyone else have a better solution to this issue? Would be sad to lose out on the performance boost you get from not applying addHandlerKey={true}
from react-router.
There are necessarily two elements, otherwise the animation isn't possible. You need keys. The DOM diff just updates the changed parts of a node tree. If that's all you're doing, there is no previous element to animate out. Make sense?
from react-router.
Yeah, makes sense. Thanks :)
from react-router.
Would be awesome to see an example of react-router and transitions. :-)
from react-router.
Well, my good sir; I am embarrassed. Thanks!
from react-router.
@iammerrick np! :)
from react-router.
@iammerrick there is also this one :P http://jsbin.com/pamon/2
from react-router.
Thanks! :-)
On Mon, Oct 27, 2014 at 4:18 PM Ryan Florence [email protected]
wrote:
@iammerrick https://github.com/iammerrick there is also this one :P
http://jsbin.com/pamon/2—
Reply to this email directly or view it on GitHub
#17 (comment).
from react-router.
so this won't work with animations between pages that are handled by the same handler?/users/john
and /users/mike
or do I just need to make sure the john
and mike
part are in the keys?
from react-router.
I tried building a version of the example using TransitionGroup's lifecycle hooks rather than CSSTransition and the hooks don't seem to get called. Am I missing something, or is this behavior only supposed to work with CSSTransitionGroup at the moment?
from react-router.
Is there a way or a pattern to make this more flexible? I don't necessarily want everything under a RouteHandler
to transition.
from react-router.
Any guidance on this?
from react-router.
I'm interested in this too, current example seems outdated #1194
from react-router.
working on this in the 1.0 branch, there's no more RouteHandler stuff going
on, its all just props (props.children usually) and so animating between
routes should be identical to any other component that's animating
children. there will be much better documentation/examples for animation
too. thanks for your patience :)
On Tue, May 19, 2015 at 8:45 PM, Daniel Belohlavek <[email protected]
wrote:
I'm interested in this too, current example seems outdated #1194
#1194—
Reply to this email directly or view it on GitHub
#17 (comment).
from react-router.
Hey @luisrudge thanks for your answer! I got that far myself but I got several warnings and an error when trying to run the code :(
Warning: Failed Context Types: Required context `routeDepth` was not specified in `RouteHandler`.
Warning: Failed Context Types: Required context `router` was not specified in `RouteHandler`.
Warning: owner-based and parent-based contexts differ (values: `undefined` vs `1`) for key (routeDepth) while mounting RouteHandler (see: http://fb.me/react-context-by-parent)
Warning: owner-based and parent-based contexts differ (values: `undefined` vs `function (props, context) [...long code...]
Uncaught TypeError: Cannot read property 'getRouteAtDepth' of undefined
I read somewhere that might have to do with having duplicate React instances. I'm using Browserify!
from react-router.
Never saw that. I'm using webpack, but this pen also doesn't throw this errors
Enviado pelo meu Windows Phone
De: Daniel Belohlavekmailto:[email protected]
Enviada em: 20/05/2015 00:27
Para: rackt/react-routermailto:[email protected]
Cc: Luís Rudgemailto:[email protected]
Assunto: Re: [react-router] Animated transitions (#17)
Hey @luisrudge thanks for your answer! I got that far myself but I got several warnings and an error when trying to run the code :(
Warning: Failed Context Types: Required context `routeDepth` was not specified in `RouteHandler`.
Warning: Failed Context Types: Required context `router` was not specified in `RouteHandler`.
Warning: owner-based and parent-based contexts differ (values: `undefined` vs `1`) for key (routeDepth) while mounting RouteHandler (see: http://fb.me/react-context-by-parent)
Warning: owner-based and parent-based contexts differ (values: `undefined` vs `function (props, context) [...long code...]
Uncaught TypeError: Cannot read property 'getRouteAtDepth' of undefined
I read somewhere that might have to do with having duplicate React instances. I'm using Browserify!
Reply to this email directly or view it on GitHub:
#17 (comment)
from react-router.
How is the progress with animations in 1.0
? :)
from react-router.
I want to create that transition.
How can i do it with [email protected], [email protected] ?
from react-router.
@misterfresh huge thanks!
from react-router.
@misterfresh many thanks!
from react-router.
thanks!!!!
from react-router.
Following the canonical example for animation I noticed that the leave animation is called when the new route could be resolved (e.g. when onEnter
is async and finished its work by calling the callback
). Say I switch from route-a
to route-b
and route-b
fetches resources, which this takes 4 seconds nothing will be animated in these 4 seconds. The onLeave
of route-a
is called immediately however.
For me this is very surprising. Is there any way to trigger the leave animation for route-a
immediately just like onLeave
is called immediately for route-a
?
from react-router.
@AlastairTaft That's gold! Especially the parts about what is interruptible and what not. Thank you. I also tried react-motion
today and struggled with its API. Do you have an example for that, too?
from react-router.
We looked at a few libs out there for this
currently we're using
https://github.com/maisano/react-router-transition
Great so far ;-)
from react-router.
@stooboo react-router-transition
sadly has the same limitation I mentioned earlier. I tried it today.
from react-router.
@donaldpipowitch cheers I missed that - thanks for the heads-up
from react-router.
Related Issues (20)
- [Bug]: Relative option is not work in useNavigate HOT 3
- [Bug]: (a11y)-Multiple accessibility issues with React-Router HOT 1
- [Bug]: The global state manager does not work in conjunction with react-router-dom HOT 1
- [Bug]: encoded # in path parameter causes route to be evaluated differently
- [Bug]: generatePath/matchPath don't handle encoding/decoding `/` the same HOT 1
- [Bug]: Support non-standard HTTP methods in Resource Routes HOT 3
- [Bug]: react-router seems to depend on vulnerable versions of path-to-regexp HOT 8
- [Bug]: react-router-dom v5 uses vulnerable version of path-to-regexp HOT 6
- [Bug]: Mount happens twice on forward navigation HOT 2
- [Bug]: type errors with `exactOptionalPropertyTypes` HOT 5
- [Bug]: React-router does not work with react 18, besides using router v6.12.0 HOT 1
- [Bug]: ScrollRestoration doesn't restore horizontal page scroll HOT 1
- [Bug]: Component does not load for JSX-returning arrow functions HOT 1
- [Bug]: Can we check shouldRevalidation before we cancel a loader? HOT 4
- [Bug]: unstable_patchRoutesOnNavigation doesn't handle multiple click correctly while loading HOT 2
- [Bug]: useLoaderData returns undefined when animating page transitions HOT 4
- [Docs]: Grammatical error. It should be "further along" not "farther along" HOT 1
- [Bug]: createRouter never defined in the CDNJS package HOT 3
- [Bug]: `JsonObject` type reports issues in Remix's `useSubmit` that are technically okay, making workarounds extense HOT 3
- Get "Expected fetch controller: :r1:" when calling fetcher.load and revalidator.revalidate HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from react-router.