This question is related to this post:
React Router v4 Match transitions using React Motion
...but I thought it deserved its own question.
I'm trying to figure out how to use the <MatchWithFade>
example taken from here:
https://react-router.now.sh/animated-transitions
The problem I'm seeing is that if I have two tabs, and I want to fade between them, I'm only seeing the fade effect on one of the two tabs, and it depends on which <MatchWithFade>
appears first in my code.
The relevant code is as follows:
const One = () => {
return (
<div style={{position:'absolute', top: 0, left: 0, width: 300, backgroundColor: 'orange'}}>
One one one one one one one one one one
</div>
)
}
const Two = () => {
return (
<div style={{position:'absolute', top: 0, left: 0, width: 300, backgroundColor: 'yellow'}}>
Two two two two two two two two two two
</div>
)
}
class AppBody extends Component {
render () {
return (
<div style={{position: 'relative'}}>
<MatchWithFade pattern='/one' component={One} />
<MatchWithFade pattern='/two' component={Two} />
</div>
)
}
}
In this example, navigating to /one
, (using the React Router <Link>
component) will cause the fade to happen, but if I navigate to /two
, there is no fade. Then, if I list <MatchWithFade pattern='/two' ... />
first, then I see the fade transition to /two
, but not /one
.
Just using <Match>
works fine, so I don't think it's a fundamental issue with how I have <BrowserRouter>
configured.
I'm hoping that I'm just doing something silly, but for the life of me, I can't figure out what. Any guidance is appreciated.
UPDATE
I couldn't figure out how to made a jsbin using React Router (couldn't figure out how to reference the methods and objects on it, since I've only ever used RR via import statements). So here's the next best thing: this is a complete example that demonstrates this issue:
import React, { Component } from 'react';
import BrowserRouter from 'react-router/BrowserRouter'
import { TransitionMotion, spring } from 'react-motion'
import Match from 'react-router/Match'
import Link from 'react-router/Link';
const MatchWithFade = ({ component:Component, ...rest }) => {
const willLeave = () => ({ opacity: spring(0) })
return (
<Match {...rest} children={({ matched, ...props }) => {
return (
<TransitionMotion
willLeave={willLeave}
styles={matched ? [ {
key: props.location.pathname,
style: { opacity: 1 },
data: props
} ] : []}
>
{interpolatedStyles => {
return (
<div>
{interpolatedStyles.map(config => (
<div
key={config.key}
style={{...config.style }}
>
<Component {...config.data}/>
</div>
))}
</div>
)
}}
</TransitionMotion>
)
}}/>
)
}
const One = () => {
return (
<div style={{position:'absolute', top: 0, left: 0, width: 300, border: '1px solid black', backgroundColor: 'orange', minHeight: 200}}>
One one one one one one one one one one<br />
One one one one one one one one one one<br />
</div>
)
}
const Two = () => {
return (
<div style={{position:'absolute', top: 0, left: 0, width: 300, border: '1px solid black', backgroundColor: 'yellow', minHeight: 200}}>
Two two two two two two two two two two<br />
Two two two two two two two two two two<br />
</div>
)
}
class App extends Component {
render () {
return (
<BrowserRouter>
<div style={{padding: 12}}>
<div style={{marginBottom: 12}}>
<Link to='/one'>One</Link> || <Link to='/two'>Two</Link>
</div>
<div style={{position: 'relative'}}>
<MatchWithFade pattern='/one' component={One} />
<MatchWithFade pattern='/two' component={Two} />
</div>
</div>
</BrowserRouter>
)
}
}
export default App;
There are only very minor differences between this MatchWithFade
, and the one taken from the React Router docs. The biggest difference is that I pulled out the zIndex
reference, but that did not affect the behavior.
If it's relevant, I started this project using create-react-app
, and I'm using React Router version 4.0.0-alpha.6
.
This is an issue with the style you're applying (or not) from the MatchWithFade
example. Add zIndex: 1
back to your willLeave
function, as this ensures the outgoing route is over top of the incoming in order to see the opacity fade.
Then add the absolute positioning back to the wrapper div you're applying the style to (styles.fill in the website example) so that they can overlap each other.
Here is a gist with your code fixed up.