不要费心阅读问题,最后有一个解决方案
我有以下路由器,使用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 步:我从/
url重新加载应用程序
Page
执行的渲染函数HomePage
execute的构造函数componentDidMount
ofHomePage
执行_
第 2 步:我导航到/courses/:courseName
Page
执行的渲染函数componentWillUnmount
ofHomePage
执行_CoursePage
execute的构造函数
注意componentDidMount
of是如何CoursePage
不触发的。这很重要,因为我需要componentDidMount
钩子。
第 3 步:我导航回/
从/courses/:courseName
Page
执行的渲染函数HomePage
execute的构造函数componentWillUnmount
ofCoursePage
执行_componentDidMount
ofHomePage
执行_
第 4 步:我再次导航回/courses/:courseName
from/
Page
执行的渲染函数componentWillUnmount
ofHomePage
执行_CoursePage
execute的构造函数componentDidMount
ofCoursePage
执行_
笔记
/courses/:courseName
如果在第 1 步中我从而不是从 重新加载,而/
不是从我放置HomePage
它的位置重新加载,则会发生完全相同的事情,CoursePage
反之亦然。- 我总是丢失第
componentDidMount
2 步(第一个重定向)。之后,所有componentDidMount
功能都按预期正常触发。 - 注意第 3 步和第 4 步中的粗体部分是如何以相反的顺序触发的。我不确定这是否有任何意义。
问题
为什么在第 2 步中 Route
component
没有触发它的componentDidMount
方法?我是否在这里遗漏了一些非常明显的东西,是我不知道的一些神秘知识还是我遇到了错误?奖励:在of
HomePage
之前触发的构造函数是怎么回事,而当我们从to导航时,相反的不是真的?componentWillUnmount
CoursePage
/
/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>
);
二)
return (
<Router>
<MockPage>
<Route exact path="/" component={Stub} />
<Route path="/courses/:courseName" component={Stub} />
</MockPage>
</Router>
);
最后更新:
发现问题!
问题显然是react-addon-perf
我在导入到SiteHeader
组件的按钮中使用的问题。Perf 工具在发生的第一次重定向时抛出了一个错误,这扰乱了随后组件的生命周期钩子。这解释了当我在一切正常children
之前移动位置的事实。SiteHeader
感谢任何打扰阅读我的胡言乱语并抱歉浪费您时间的人。