使用 React Router v4 和 MatchWithFade 嵌套匹配路由
Nested Match routes with React Router v4 and MatchWithFade
此问题是此问题的后续问题:
我有另一个(可能很愚蠢的)关于使用 MatchWithFade
和 React Router v4 的问题。我想做的是嵌套路由,所以顶级组件可能有:
<MatchWithFade pattern='/one' component={One} />
...然后 One
可能有这个:
<Match pattern='/one/one' Component={OneOne} />
这并没有让我觉得这是一种不寻常的模式(尽管也许是)。无论如何,我观察到的行为是,使用上面的示例,如果我加载 OneOne
,它会被装载,然后立即调用 componentWillUnmount
。如果我猜的话,我会说 TransitionMotion
正在跟踪 OneOne
的一个(可能是隐藏的)实例,一旦转换完成,它就会卸载那个隐藏的组件。就基本的UI而言,呈现OneOne
。然而,如果 componentWillUnmount
做了任何清理(比如,从 Redux 中删除一些东西),那么当然会触发该操作,并且与 OneOne
相关的任何数据都会被清除。
这是一个说明问题的完整示例:
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 styles = {
fill: { position: 'absolute', top: 0, left: 0 }
};
const MatchWithFade = ({ component:Component, ...rest }) => {
const willLeave = () => ({ zIndex: 1, 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={{...styles.fill, ...config.style }}>
<Component {...config.data}/>
</div>
))}
</div>
)
}}
</TransitionMotion>
)
}}/>
)
}
const TwoOne = () => {
return (
<div>Two One</div>
)
}
class TwoTwo extends Component {
componentWillUnmount() {
console.log("TwoTwo will unmount")
}
render () {
return (
<div>Two Two</div>
)
}
}
const TwoHome = () => {
return (
<div>Two Home</div>
)
}
class One extends Component {
componentWillUnmount () {
console.log("ONE UNMOUNTING")
}
render () {
return (
<div style={{ 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={{ width: 300, border: '1px solid black', backgroundColor: 'yellow', minHeight: 200}}>
<Match pattern='/two/one' component={TwoOne} />
<Match pattern='/two/two' component={TwoTwo} />
<Match pattern='/two(/)?' exactly={true} component={TwoHome} />
</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>
|| <Link to='/two/one'>Two One</Link>
|| <Link to='/two/two'>Two Two</Link>
</div>
<div style={{position: 'relative'}}>
<MatchWithFade pattern='/one' component={One} />
<MatchWithFade pattern='/two' component={Two} />
</div>
</div>
</BrowserRouter>
)
}
}
export default App;
如果加载它并打开控制台,请在 One
和 Two
链接之间切换。您会在 UI 中看到淡入淡出,当从一到二的转换完成时,您会在控制台中看到 "ONE UNMOUNTING"。原来如此。
现在,在 Two One
和 Two Two
之间单击。在这种情况下,单击 Two One
时,您会立即在控制台中看到 "TwoTwo will unmount",这很好。但是,如果您单击 Two Two
,您将在大约一秒后看到 "TwoTwo will unmount"——我认为这是父 MatchWithFade
执行所花费的时间。
所以我不确定这里发生了什么。我的代码刚刚被破坏了吗?我在做 RRv4 不支持的事情吗?我发现了一个错误吗?
任何 help/guidance 不胜感激!
您的问题是您使用 props.location.pathname
作为密钥。这对于一个组件来说应该总是相同的,但是你编写它的方式,它会在你每次导航时发生变化。尝试改变这个:
const styles = {
fill: { position: 'absolute', top: 0, left: 0 }
};
至:
const styles = {
fill: { position: 'relative', top: 0, left: 0 }
};
你会看到你正在渲染 <Two>
的两个实例(每个键一个)。
如果您使用常量 key
,例如 rest.pattern
(与此 <Match>
关联的模式),您的问题就会消失。
styles={matched ? [ {
key: rest.pattern,
style: { opacity: 1 },
data: props
} ] : []}
此问题是此问题的后续问题:
我有另一个(可能很愚蠢的)关于使用 MatchWithFade
和 React Router v4 的问题。我想做的是嵌套路由,所以顶级组件可能有:
<MatchWithFade pattern='/one' component={One} />
...然后 One
可能有这个:
<Match pattern='/one/one' Component={OneOne} />
这并没有让我觉得这是一种不寻常的模式(尽管也许是)。无论如何,我观察到的行为是,使用上面的示例,如果我加载 OneOne
,它会被装载,然后立即调用 componentWillUnmount
。如果我猜的话,我会说 TransitionMotion
正在跟踪 OneOne
的一个(可能是隐藏的)实例,一旦转换完成,它就会卸载那个隐藏的组件。就基本的UI而言,呈现OneOne
。然而,如果 componentWillUnmount
做了任何清理(比如,从 Redux 中删除一些东西),那么当然会触发该操作,并且与 OneOne
相关的任何数据都会被清除。
这是一个说明问题的完整示例:
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 styles = {
fill: { position: 'absolute', top: 0, left: 0 }
};
const MatchWithFade = ({ component:Component, ...rest }) => {
const willLeave = () => ({ zIndex: 1, 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={{...styles.fill, ...config.style }}>
<Component {...config.data}/>
</div>
))}
</div>
)
}}
</TransitionMotion>
)
}}/>
)
}
const TwoOne = () => {
return (
<div>Two One</div>
)
}
class TwoTwo extends Component {
componentWillUnmount() {
console.log("TwoTwo will unmount")
}
render () {
return (
<div>Two Two</div>
)
}
}
const TwoHome = () => {
return (
<div>Two Home</div>
)
}
class One extends Component {
componentWillUnmount () {
console.log("ONE UNMOUNTING")
}
render () {
return (
<div style={{ 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={{ width: 300, border: '1px solid black', backgroundColor: 'yellow', minHeight: 200}}>
<Match pattern='/two/one' component={TwoOne} />
<Match pattern='/two/two' component={TwoTwo} />
<Match pattern='/two(/)?' exactly={true} component={TwoHome} />
</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>
|| <Link to='/two/one'>Two One</Link>
|| <Link to='/two/two'>Two Two</Link>
</div>
<div style={{position: 'relative'}}>
<MatchWithFade pattern='/one' component={One} />
<MatchWithFade pattern='/two' component={Two} />
</div>
</div>
</BrowserRouter>
)
}
}
export default App;
如果加载它并打开控制台,请在 One
和 Two
链接之间切换。您会在 UI 中看到淡入淡出,当从一到二的转换完成时,您会在控制台中看到 "ONE UNMOUNTING"。原来如此。
现在,在 Two One
和 Two Two
之间单击。在这种情况下,单击 Two One
时,您会立即在控制台中看到 "TwoTwo will unmount",这很好。但是,如果您单击 Two Two
,您将在大约一秒后看到 "TwoTwo will unmount"——我认为这是父 MatchWithFade
执行所花费的时间。
所以我不确定这里发生了什么。我的代码刚刚被破坏了吗?我在做 RRv4 不支持的事情吗?我发现了一个错误吗?
任何 help/guidance 不胜感激!
您的问题是您使用 props.location.pathname
作为密钥。这对于一个组件来说应该总是相同的,但是你编写它的方式,它会在你每次导航时发生变化。尝试改变这个:
const styles = {
fill: { position: 'absolute', top: 0, left: 0 }
};
至:
const styles = {
fill: { position: 'relative', top: 0, left: 0 }
};
你会看到你正在渲染 <Two>
的两个实例(每个键一个)。
如果您使用常量 key
,例如 rest.pattern
(与此 <Match>
关联的模式),您的问题就会消失。
styles={matched ? [ {
key: rest.pattern,
style: { opacity: 1 },
data: props
} ] : []}