2016-12-29 131 views
0

这个问题是一个后续的:使用嵌套比赛路线阵营路由器v4和MatchWithFade

Trouble with React Router v4 and MatchWithFade

我有另一个(可能很傻)问题有关使用MatchWithFade和应对路由器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; 

如果加载这一点,打开控制台,该OneTwo链接之间切换。您将看到UI中出现交叉淡入淡出,并且在从One到Two的转换完成时,控制台中会显示“ONE UNMOUNTING”。这是对的。

现在,点击Two OneTwo Two。在这种情况下,单击Two One时,您会立即看到控制台中的“TwoTwo将卸载”,这很好。但是,如果您点击Two Two,您会在大约一秒后看到“TwoTwo将卸载” - 我认为这是父母MatchWithFade需要执行的时间。

所以我不确定这里发生了什么。我的代码刚刚被破坏了吗?我正在做RRv4无法支持的事情吗?我发现了一个错误?

任何帮助/指导表示赞赏!

回答

1

您的问题是您使用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 
} ] : []} 
+0

啊!有趣! 'MatchWithFade'代码是从React-Router文档逐字记录的,所以我认为它完全是它应该的。现在我看到'props.location.pathname'和'rest.pattern'之间的区别。 'rest.pattern'是与当前匹配组件匹配的路径的一部分,props.location.pathname是完整路径,这意味着是,密钥更改,因此加载多个实例。所以这可能意味着RR文档应该更新为使用rest.pattern而不是props.location.pathname,这样其他人就不会遇到这个问题。 – hairbo

+0

理由可能有点复杂,但我认为它的方式是这样的:1)每个“”都是唯一的。如果你有两个,那是两个不同的动画。 2)为一个''中的每个键创建一个元素。在文档示例中,应该为每个位置渲染一个新的'',因此使用'props.location.pathname'可以很好地发挥关键作用。在你的代码中,你只需要渲染一个'',所以你需要一个不会改变的密钥。 –

+0

对,这很有道理。是的,我的头脑很难找到它,但它已经开始渗透进来了。要清楚,在他们的例子中,“rest.pattern”可以作为一个键,就像props.location.pathname '是的,对吧?而且它还有一个额外的好处,就是稍微有点笨蛋,因为有人(比如,哦,我)可以滑动该代码并对其进行修改,而不用担心更改该密钥。 – hairbo