Route 中的渲染组件不会触发其 componentDidMount
Rendered component in Route does not fire its componentDidMount
请不要费心阅读问题,最后有解决方案
我有以下路由器,使用 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
的构造函数执行
HomePage
的componentDidMount
执行
第 2 步:我导航到 /courses/:courseName
Page
的渲染函数执行
HomePage
的componentWillUnmount
执行
CoursePage
的构造函数执行
注意 CoursePage
的 componentDidMount
如何不触发 。这很重要,因为我需要 componentDidMount
钩子。
第 3 步:我从 /courses/:courseName
导航回 /
Page
的渲染函数执行
HomePage
的构造函数执行
CoursePage
的componentWillUnmount
执行
HomePage
的componentDidMount
执行
第 4 步:我再次从 /
导航回 /courses/:courseName
Page
的渲染函数执行
HomePage
的componentWillUnmount
执行
CoursePage
的构造函数执行
CoursePage
的componentDidMount
执行
注释
- 如果在第 1 步中我从
/courses/:courseName
而不是 /
重新加载,而不是我放置 HomePage
的位置它会读取 CoursePage
反之亦然。
- 我总是丢失第 2 步(第一个重定向)的
componentDidMount
。 之后所有 componentDidMount
函数都按预期正常启动。
- 注意第 3 步和第 4 步中的粗体部分是如何以相反的顺序触发的。我不确定这是否有任何意义。
问题
为什么在步骤 2 中路由的 component
没有触发它的 componentDidMount
方法? 我在这里遗漏了一些非常明显的东西吗,是我不知道的神秘知识还是我遇到了错误?
Bonus:在 CoursePage
的 componentWillUnmount
之前触发 HomePage
的构造函数有何处理,而当我们从 /
导航到 /courses/:coursName
时,相反的情况不成立 ?
When you use component (instead of render, below) the router uses
React.createElement to create a new React element from the given
component. That means if you provide an inline function, you are
creating a new component every render. This results in the existing
component unmounting and the new component mounting instead of just
updating the existing component.
这让我的问题更没有意义
我找到了解决方法
在我的 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
调用丢失:
A)
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>
);
最终更新:
找到问题了!
问题显然是我在导入到 SiteHeader
组件的按钮中使用的 react-addon-perf
。 Perf 工具在发生的第一个重定向时抛出错误,这会扰乱后续组件的生命周期挂钩。这解释了一个事实,即当我将 children
的位置移动到 SiteHeader
之前时,一切正常。感谢任何费心阅读我的胡言乱语的人,抱歉浪费你的时间。
使用 React-route 4,您可以像这样编写页面。与路线匹配的每条路线都将显示在视图中。 React-route 4 不再需要 props.children。
这是适合我的代码。
如果我转到“/”,则会呈现页眉、主页和页脚,包括 DidMount。
如果我转到“/courses/1”,则会呈现页眉、主页、课程和页脚,包括 DidMount
import { BrowserRouter as Router, Route } from 'react-router-dom';
import React, { PropTypes } from 'react';
import SiteFooter from './components/App/siteFooter'
import SiteHeader from './components/App/siteHeader'
import CoursePage from './components/App/coursePage'
import HomePage from './components/App/homePage'
export default class Routes extends React.Component {
render() {
return (
<Router>
<div>
<Route path="/" component={SiteHeader} />
<Route path="/" component={HomePage} />
<Route path="/courses/:courseName" component={CoursePage} />
<Route path="/" component={SiteFooter} />
</div>
</Router>
);
}
}
请不要费心阅读问题,最后有解决方案
我有以下路由器,使用 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
的构造函数执行HomePage
的componentDidMount
执行
第 2 步:我导航到 /courses/:courseName
Page
的渲染函数执行HomePage
的componentWillUnmount
执行CoursePage
的构造函数执行
注意 CoursePage
的 componentDidMount
如何不触发 。这很重要,因为我需要 componentDidMount
钩子。
第 3 步:我从 /courses/:courseName
/
Page
的渲染函数执行HomePage
的构造函数执行CoursePage
的componentWillUnmount
执行HomePage
的componentDidMount
执行
第 4 步:我再次从 /
导航回 /courses/:courseName
Page
的渲染函数执行HomePage
的componentWillUnmount
执行CoursePage
的构造函数执行CoursePage
的componentDidMount
执行
注释
- 如果在第 1 步中我从
/courses/:courseName
而不是/
重新加载,而不是我放置HomePage
的位置它会读取CoursePage
反之亦然。 - 我总是丢失第 2 步(第一个重定向)的
componentDidMount
。 之后所有componentDidMount
函数都按预期正常启动。 - 注意第 3 步和第 4 步中的粗体部分是如何以相反的顺序触发的。我不确定这是否有任何意义。
问题
为什么在步骤 2 中路由的
component
没有触发它的componentDidMount
方法? 我在这里遗漏了一些非常明显的东西吗,是我不知道的神秘知识还是我遇到了错误?Bonus:在
CoursePage
的componentWillUnmount
之前触发HomePage
的构造函数有何处理,而当我们从/
导航到/courses/:coursName
时,相反的情况不成立 ?
When you use component (instead of render, below) the router uses React.createElement to create a new React element from the given component. That means if you provide an inline function, you are creating a new component every render. This results in the existing component unmounting and the new component mounting instead of just updating the existing component.
这让我的问题更没有意义
我找到了解决方法
在我的 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
调用丢失:
A)
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>
);
最终更新:
找到问题了!
问题显然是我在导入到 SiteHeader
组件的按钮中使用的 react-addon-perf
。 Perf 工具在发生的第一个重定向时抛出错误,这会扰乱后续组件的生命周期挂钩。这解释了一个事实,即当我将 children
的位置移动到 SiteHeader
之前时,一切正常。感谢任何费心阅读我的胡言乱语的人,抱歉浪费你的时间。
使用 React-route 4,您可以像这样编写页面。与路线匹配的每条路线都将显示在视图中。 React-route 4 不再需要 props.children。
这是适合我的代码。 如果我转到“/”,则会呈现页眉、主页和页脚,包括 DidMount。 如果我转到“/courses/1”,则会呈现页眉、主页、课程和页脚,包括 DidMount
import { BrowserRouter as Router, Route } from 'react-router-dom';
import React, { PropTypes } from 'react';
import SiteFooter from './components/App/siteFooter'
import SiteHeader from './components/App/siteHeader'
import CoursePage from './components/App/coursePage'
import HomePage from './components/App/homePage'
export default class Routes extends React.Component {
render() {
return (
<Router>
<div>
<Route path="/" component={SiteHeader} />
<Route path="/" component={HomePage} />
<Route path="/courses/:courseName" component={CoursePage} />
<Route path="/" component={SiteFooter} />
</div>
</Router>
);
}
}