【发布时间】:2017-04-19 00:48:26
【问题描述】:
不要费心阅读问题,最后有一个解决方案
我有以下路由器,使用 react-router 4
return (
<Router>
<Page>
<Route exact path="/" component={HomePage} />
<Route path="/courses/:courseName" component={CoursePage} />
</Page>
</Router>
);
Page 组件如下所示:
function Page(props) {
const { children } = props;
return (
<div className="page">
<SiteHeader />
{children}
<SiteFooter />
</div>
);
}
SiteHeader、SiteFooter、HomePage 和 CoursePage 是纯表示组件;他们把道具吐出来。没有连接到 redux 商店或任何东西。 HomePage 和 CoursePage 被定义为类。
在HomePage 和CoursePage 内部,我需要使用componentDidMount 挂钩,以便与DOM 交互。
现在发生了以下奇怪的事情:
第 1 步:我从 / 网址重新加载应用程序
-
Page的render函数执行 -
HomePage的构造函数执行 -
HomePage的componentDidMount执行
第 2 步:我导航到 /courses/:courseName
-
Page的render函数执行 -
HomePage的componentWillUnmount执行 -
CoursePage的构造函数执行
注意 CoursePage 的 componentDidMount 是如何不触发的。这很重要,因为我需要 componentDidMount 钩子。
第 3 步:我从 /courses/:courseName 导航回 /
-
Page的render函数执行 HomePage的构造函数执行CoursePage的componentWillUnmount执行-
HomePage的componentDidMount执行
第 4 步:我再次从 / 导航回 /courses/:courseName
-
Page的render函数执行 HomePage的componentWillUnmount执行CoursePage的构造函数执行-
CoursePage的componentDidMount执行
注意事项
- 如果在 STEP 1 中我从
/courses/:courseName而不是/重新加载,则会发生完全相同的事情,而不是我放置HomePage的位置,它会读取CoursePage,反之亦然。 -
我总是丢失 STEP 2 的
componentDidMount(第一次重定向)。 之后,所有componentDidMount函数按预期正常触发。 - 注意第 3 步和第 4 步中的粗体部分是如何以相反的顺序触发的。我不确定这是否有任何意义。
问题
为什么在 STEP 2 中 Route 的
component没有触发其componentDidMount方法? 我在这里遗漏了一些非常明显的东西,是我不知道的一些神秘知识还是我遇到错误了吗?奖励:在
CoursePage的componentWillUnmount之前触发HomePage的构造函数是怎么回事,而当我们从@987654374 导航时,反面不是真的@到/courses/:coursName?
当你使用组件(而不是渲染,如下)时,路由器使用 React.createElement 从给定的创建一个新的 React 元素 零件。 这意味着如果你提供一个内联函数,你就是 每次渲染创建一个新组件。这导致现有 组件卸载和新组件安装,而不仅仅是 更新现有组件。
这让我的问题更没有意义
我找到的解决方法
在我的Page 组件中,如果我像这样简单地移动children 的顺序
function Page(props) {
const { children } = props;
return (
<div className="page">
{children} // MOVED FIRST
<SiteHeader />
<SiteFooter />
</div>
);
}
那么问题就解决了,但是我不认为这是一个合适的解决方案。我真的很想知道发生了什么,因为它让我心碎。
编辑:
为了简洁和使用例场景更简单,对问题进行了编辑
更新 - 进一步观察
让Stub.jsx 成为下面的组件
import React from 'react';
class Stub extends React.Component {
constructor(props) {
super(props);
debugger;
}
componentDidMount() { debugger; }
componentWillUnmount() { debugger; }
render() { return <div style={{ margin: '100px 0' }}><span>Hello</span></div>; }
}
export default Stub;
和MockPage.jsx 是下面的组件
function MockPage(props) {
const { children } = props;
debugger;
return (
<div className="page">
<div>Hi</div> //Instead of SiteHeader
{children}
<div>Hi</div> //Instead of SiteFooter
</div>
);
}
那么以下所有配置都可以正常播放,意味着在重定向之间不会丢失componentDidMount 调用:
一)
return (
<Router>
<div>
<Route exact path="/" component={Stub} />
<Route path="/courses/:courseName" component={Stub} />
</div>
</Router>
);
B)
return (
<Router>
<MockPage>
<Route exact path="/" component={Stub} />
<Route path="/courses/:courseName" component={Stub} />
</MockPage>
</Router>
);
最终更新:
找到问题了!
问题显然是我在一个按钮中使用的react-addon-perf,我正在导入我的SiteHeader 组件。 Perf 工具在发生的第一次重定向时抛出了一个错误,这扰乱了随后组件的生命周期钩子。这就解释了当我将children 的位置移到SiteHeader 之前的事实,一切正常。感谢所有打扰阅读我的胡言乱语的人,抱歉浪费了您的时间。
【问题讨论】:
标签: javascript reactjs react-router react-router-v4