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>
  );
}

SiteHeaderSiteFooterHomePageCoursePage 是纯粹的展示组件;他们拿走道具,然后吐出标记。没有连接到 redux 商店或任何东西。 HomePageCoursePage 定义为 类.

HomePageCoursePage 中,我需要使用 componentDidMount 钩子,以便与 DOM.

进行交互

现在发生了以下奇怪的事情:

第 1 步:我从 / url

重新加载应用程序

第 2 步:我导航到 /courses/:courseName

注意 CoursePagecomponentDidMount 如何不触发 。这很重要,因为我需要 componentDidMount 钩子。

第 3 步:我从 /courses/:courseName

导航回 /

第 4 步:我再次从 / 导航回 /courses/:courseName

注释

问题

每个 documentation

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>
    );
  }
}