Comments (26)
The solution from @akeelm is very nice, but I still had a problem with the footer of the page to toggle up and down. Using code below this is fixed.
<RouteTransition
pathname={this.props.location.pathname}
atEnter={{ opacity: 0, foo: 0 }}
atLeave={{ opacity: 0, foo: 2 }}
atActive={{ opacity: 1, foo: 1 }}
mapStyles={(styles) => {
return {
position: (styles.foo <= 1) ? 'relative': 'absolute',
width: '100%',
height: '100%',
opacity: styles.opacity
}
}}>
I only still have the footer problem when I toggle routes really quick.
from react-router-transition.
I have a similar solution, it just fades only the appearing div, and hides the older one:
<RouteTransition
pathname={this.props.location.pathname}
atEnter={{ opacity: 0 }}
atLeave={{ opacity: 2 }}
atActive={{ opacity: 1 }}
mapStyles={styles => {
if(styles.opacity > 1){
return { display: 'none'}
}
return { opacity: styles.opacity}
}}
>
{this.props.children}
</RouteTransition>
from react-router-transition.
I think that the issue he's referring (it's just a guess) is this:
https://gfycat.com/JadedUnrealisticBoto
Without an absolute position, this will happen. (This is using the presets.pop)
from react-router-transition.
Unfortunately, I didn't save my code because I had changed my mind about using transitions, but you should be able to do it by doing something like:
// Name of the container, forgot the name
.container {
display: grid;
grid-template-areas:"MyCustomAreaName";
}
// Forces all children under container to be in the same space/area
.container > div{
grid-area: MyCustomAreaName;
}
Note that I don't remember the names of the classes, so I suggest you check them using the Inspector, the child class should be the one that has opacity and all the stuff, while the parent is the container.
Also if you want a wider browser support, you should do the same thing without using "area" feature. ( e.g. grid-template-columns
and things like that )
from react-router-transition.
I have modified @JurJean 's solution with a pop config. Works great. Same issue with fast route transitions, though (which is a shame, as one of the motivations for react-motion was to improve UX for cancelled transitions).
const popConfig = { stiffness: 360, damping: 25 };
export const pop = {
atEnter: {
transitionIndex: 0,
scale: 0.8,
opacity: 0,
},
atLeave: {
scale: spring(0.8, popConfig),
opacity: spring(0, popConfig),
transitionIndex: 2,
},
atActive: {
scale: spring(1, popConfig),
opacity: 1,
transitionIndex: 1,
},
mapStyles: styles => ({
position: styles.transitionIndex <= 1 ? 'relative' : 'absolute',
width: '100%',
height: '100%',
transform: `scale(${styles.scale})`,
opacity: styles.opacity,
}),
};
from react-router-transition.
I achieved this by applying the css to the inner div (created in renderRoute). To do this I added the css through mapStyles in my presets (see noTransition below):
const fadeTransitionConfig = { stiffness: 200, damping: 22 };
const popTransitionConfig = { stiffness: 360, damping: 25 };
const slideTransitionConfig = { stiffness: 330, damping: 30 };
noTransition = {
atEnter: {
opacity: 1,
scale: 1,
offset: 0
},
atLeave: {
opacity: spring(1, fadeTransitionConfig),
scale: spring(1, popTransitionConfig),
offset: spring(0, slideTransitionConfig)
},
atActive: {
opacity: spring(1, fadeTransitionConfig),
scale: spring(1, popTransitionConfig),
offset: spring(0, slideTransitionConfig)
},
mapStyles(styles) {
return {
position: 'absolute',
boxSizing: 'border-box',
width: '100%',
height: '100%',
opacity: styles.opacity,
transform: 'translateX(' + styles.offset + '%) scale(' + styles.scale + ')'
}
}
};
fadeTransition = {
atEnter: Object.assign({}, noTransition.atEnter, { opacity: 0 }),
atLeave: Object.assign({}, noTransition.atLeave, { opacity: spring(0, fadeTransitionConfig) }),
atActive: Object.assign({}, noTransition.atLeave, { opacity: spring(1, fadeTransitionConfig) }),
mapStyles: noTransition.mapStyles
};
popTransition = {
atEnter: Object.assign({}, noTransition.atEnter, { scale: 0.8 }),
atLeave: Object.assign({}, noTransition.atLeave, { scale: spring(0.8, popTransitionConfig) }),
atActive: Object.assign({}, noTransition.atLeave, { scale: spring(1, popTransitionConfig) }),
mapStyles: noTransition.mapStyles
};
slideLeftTransition = {
atEnter: Object.assign({}, noTransition.atEnter, { offset: 100 }),
atLeave: Object.assign({}, noTransition.atLeave, { offset: spring(-100, slideTransitionConfig) }),
atActive: Object.assign({}, noTransition.atLeave, { offset: spring(0, slideTransitionConfig) }),
mapStyles: noTransition.mapStyles
};
slideRightTransition = {
atEnter: Object.assign({}, noTransition.atEnter, { offset: -100 }),
atLeave: Object.assign({}, noTransition.atLeave, { offset: spring(100, slideTransitionConfig) }),
atActive: Object.assign({}, noTransition.atLeave, { offset: spring(0, slideTransitionConfig) }),
mapStyles: noTransition.mapStyles
};
Implementation:
<RouteTransition pathname={this.props.location.pathname} {...this.state.transition}>
{
React.cloneElement(this.props.children, {setTransition: this.setTransition})
}
</RouteTransition>
From the child I pass the preset when I click on the react-router link for example, and set whatever transition state I want on RouteTransition
@maisano - I ended up doing the above (having a base i.e. 'noTransition') because
- My app base has a RouteTransition but I may not want to transition so basically that is the default. Avoids having to change the structure of the container
- More importantly, I found that if I only mapped the styles for the particular transition and I switched between "different ones" i.e. fade and slide it wouldn't transition correctly. I also avoided React complaining that I mutated the props because they are different ;) This fixed it and it seems to work well now
Would like to hear your thoughts on this approach i.e. performance considerations interpolating props that don't actually change. I suspect it shouldn't be an issue but not 100% sure.
Thanks for this wrapper - excellent work!
from react-router-transition.
@arkist: hm, i haven't given this a ton of thought–to be honest, most of the times i have animated routes, they've been wrapped in such a way where height was not an issue (they made up the entire page or the overflow was scrollable, etc). can you give some more background into your layout/how you're using this?
@abelovic: i'm glad you're enjoying the project! thanks for the feedback. you're correct in your approach if you want to dynamically toggle between different transition settings–react-motion
requires the same keys to interpolate, and introducing new ones/removing old ones won't work.
as per your question on performance, i don't see this being an issue. the api recently changed and i haven't looked at the internals since, though i recall TransitionMotion
only needing to interpolate keys when their destination values change. in this example, nothing changes so you should be fine.
one small thing i did notice is that you're cloning children to pass in the setTransition
callback–if you wanted to avoid this you could use state from history instead, pulling it out in your root component as needed, e.g. using a Link
with a state
prop (<Link to={path} state={{transition: 'slideLeft'}}>
) where you reference that state in your handler via this.props.history.state.transition
.
from react-router-transition.
@amorino i debated for a while whether to add absolute positions to the presets, or even include the presets at all. it probably makes more sense to add position: absolute
to the mapStyles
of each preset. it's easy enough to override and they're sort of broken without. feel free to pr or i can update this sometime over the weekend.
from react-router-transition.
@amorino exactly. that's the what I encountered.
@maisano I'm a newbie in motion/transitioning so don't know this issue is common or not. see below codes, please.
What I learn from @abelovic's code is set position: absolute; width: 100%; height: 100%
and put all the Component inside of <RouteTransition />
works fine. thanks! and noTransition-default strategy looks good.
but I think it seems to be still a problem: how about nested Component's transition? (not about path)
// <Header/> and <Footer/> don't need transition (always there)
// so they're on outside of <RouteTransition />.
// in this case, you can't set `position: absolute` to route because of Header&Footer.
<Header />
<RouteTransition
pathname={this.props.location.pathname}
atEnter={{opacity: 0, position: 'relative'}}
atLeave={{opacity: 0, position: 'absolute'}}
atActive={{opacity: 1, position: 'relative'}}
mapStyles={styles => {
return {
position: styles.position, // so I wanna something like this but it is impossible! :(
opacity: styles.opacity
};
}}
>
{this.props.children}
</RouteTransition>
<Footer />
from react-router-transition.
@arkist: ah, got it. so the issue with the code posted is that the objects that get passed to atEnter
, atLeave
and atActive
get passed to react-motion for numeric interpolation–this won't work with strings.
i'm not currently sure the best way to handle dynamic, unbounded route heights, though i'm sure this is a common use case. i'll have to give it some more thought.
from react-router-transition.
@maisano good :) I'll try to find a way, too. thanks for this project!
from react-router-transition.
@maisano - thanks for the tip that is a much cleaner way to do it :) The API of react router changed in 2.0 so if anyone is interested this is what I did:
The mixin ContextRoute is deprecated so you will have to get the location object by passing context (its explained in the 2.0.0 change docs)
@arkist - I actually transition my header so the label and buttons etc... are encapsulated inside the react component (my view). If you do this one trick I did is to make the container color the same color as the header otherwise you will see the white background (or whatever color your container is) as the transition occurs.
However it sounds like you would rather have a fixed header where the content is the same for all views you transition to i.e. a common menu or application header
Could you not just do the following (untested)?
.header {
height: 50px
top: 0
position: absolute
}
/* this is passed using mapStyles /
.route-transition {
height: calc(100% - 100px) / height of header and footer - since it is app specific probably ok to just add it to your presets? */
top: 50px
position: absolute
}
.footer {
height: 50px
bottom: 0
position: absolute
}
from react-router-transition.
Sorry code snippet got removed
<Link to={{ pathname: '/Home', state: {transition: slideRight} }} />
from react-router-transition.
@abelovic thanks for the awesome tip! :)
browser support is a problem only. http://caniuse.com/#search=calc
from react-router-transition.
Well looks like you would mainly loose Opera mini (Blackberry I think) and IE 8 support but look at this:
https://facebook.github.io/react/blog/2016/01/12/discontinuing-ie8-support.html
For me this is not a problem and I use calc all the time. If you do need to support these browsers however you might be able to use something like:
https://github.com/souporserious/react-measure
and just do the calculations in react :)
from react-router-transition.
Just my $0.02:
Instead of percentage I am using:
height:calc(100vh - 50px);
in my mapStyles() function instead of percentage. This makes it so that you don't have to worry about the geometry of the parent component. (100vh is the height of the window in pixels, 50px is the height of my header)
from react-router-transition.
This may not be the best solution - but I managed to get @arkist's desired effect by swapping the non-numeric values when one of the animating properties reached a desired value inside the mapStyles function:
<RouteTransition
pathname={this.props.location.pathname}
atEnter={{ opacity: 0 }}
atLeave={{ opacity: 0 }}
atActive={{ opacity: 1 }}
mapStyles={(styles) => {
return {
position: (styles.opacity === 1) ? undefined: 'absolute',
width: (styles.opacity === 1) ? undefined : '100%',
height: (styles.opacity === 1) ? undefined : '100%',
opacity: styles.opacity,
}
}}>
{this.props.children}
</RouteTransition>
Now I don't need to worry about my transitioning elements blowing out the layout, but also as soon as they're done animating in I can remove the style and they'll revert to their original css.
from react-router-transition.
I had issues with this too, but even with some of the workarounds here, couldn't get it working properly.
So here's my amendment to one of the workarounds. Notice I do the switch to absolute positioning just before the div disappears.
<RouteTransition
pathname={this.props.location.pathname}
atEnter={{ opacity: 0 }}
atLeave={{ opacity: 0 }}
atActive={{ opacity: 1 }}
mapStyles={(styles) => {
return {
position: (styles.opacity > 0.3) ? 'relative': 'absolute',
boxSizing: 'border-box',
width: '100%',
height: '100%',
opacity: styles.opacity,
transform: 'translateX(' + styles.offset + '%) scale(' + styles.scale + ')'
}
}}
>
from react-router-transition.
Hello,
@akeelm The fade effect works quite well with your code. However do you think we could achieve the same for slide effect without absolute positionning ?
from react-router-transition.
It would be so helpful to have a codepen example for some of these. I've switched from easy-transition to react-motion to react-router-transition but transitionX fails for all of them. I know this can be fixed. Has someone tried setting the height of the children components\pages with JS or using a css property that does not require position:absolute?
from react-router-transition.
I have tried @JurJean solution works great. Except for when switching route back before the first animation is done. Then you have both elements having position absolute, which means the container collapses until the animations are done. Any solution for this?
from react-router-transition.
For those looking for an answer to this problem, look no further!
I have found a solution of making the transitions overlap without using position:absolute or floats.
How did I do it?
Simple, use CSS Grid on the parent, then have both of the childs use the same grid-area.
This will make both of the elements use the same area, allowing them to overlap while keeping the layout completely functional as before.
The only drawback is IE and it's partial support for CSS Grids, but if you live in the present like most of us then it shouldn't be a big of an issue. Otherwise, you can simply disable the transition for the unsupported browsers.
from react-router-transition.
Hey @Xerios 👋
Could you share some code with your solution?
On my project I'm using flexbox
everywhere and I have some sort of "jumping" when I use @aakarim solution.
from react-router-transition.
good idea. I am now using grid if support. I check for grid with css feature detection and fallback to position absolute/relative if not supported. Thanks
from react-router-transition.
Thanks @akeelm For the solution.
I face slightly different type of problem my Carousel was not working and after applying your following code
mapStyles={(styles) => { return { position: (styles.opacity > 0.3) ? 'relative': 'absolute', boxSizing: 'border-box', width: '100%', height: '100%', opacity: styles.opacity, transform: 'translateX(' + styles.offset + '%) scale(' + styles.scale + ')' } }}
from react-router-transition.
here's a very simple example to get the basics
https://github.com/ueeieiie/simple-route-transitions
from react-router-transition.
Related Issues (20)
- Very first transition is a bit buggy, after that it's smooth HOT 1
- Slide animation HOT 1
- AnimatedSwitch throws error if maximum update depth is exceeded within a HOC HOT 2
- componentWillReceiveProps is going to be deprecated HOT 5
- Transition works on the first time, but Component goes missing on the second time. HOT 2
- Attempted import error: 'useLocation' is not exported from 'react-router-dom' HOT 8
- Tests failing with error: SyntaxError: Cannot use import statement outside a module after upgrading to 2.0.0 HOT 5
- Transitioning between dynamic routes
- Entering Component not animated
- support v6 HOT 1
- Is there a way for a transitioned component to know about it?
- Warning: componentWillReceiveProps HOT 2
- Update to React version 17.X? HOT 3
- Is there any way to add/remove classes `atEnter`, `atLeave`, and `atActive`? HOT 1
- Support "prefers-reduced-motion"
- Transition duration missing? HOT 1
- Notifying transitioned component that transition has started (instead of ComponentWillUnmount)
- Source or example of example site transitions HOT 1
- Attempted import error: 'Switch' is not exported from 'react-router-dom' HOT 2
- use in React-routerV6 , error: `Uncaught TypeError: pathname.match is not a function`
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-transition.