【问题标题】:Rendered component in Route does not fire its componentDidMountRoute 中的渲染组件不会触发其 componentDidMount
【发布时间】: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>
  );
}

SiteHeaderSiteFooterHomePageCoursePage 是纯表示组件;他们把道具吐出来。没有连接到 redux 商店或任何东西。 HomePageCoursePage 被定义为类。

HomePageCoursePage 内部,我需要使用componentDidMount 挂钩,以便与DOM 交互。

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

第 1 步:我从 / 网址重新加载应用程序

  • Page的render函数执行
  • HomePage的构造函数执行
  • HomePagecomponentDidMount 执行

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

  • Page的render函数执行
  • HomePagecomponentWillUnmount 执行
  • CoursePage的构造函数执行

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

第 3 步:我从 /courses/:courseName 导航回 /

  • Page的render函数执行
  • HomePage的构造函数执行
  • CoursePagecomponentWillUnmount 执行
  • HomePagecomponentDidMount 执行

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

  • Page的render函数执行
  • HomePagecomponentWillUnmount 执行
  • CoursePage的构造函数执行
  • CoursePagecomponentDidMount 执行

注意事项

  • 如果在 STEP 1 中我从 /courses/:courseName 而不是 / 重新加载,则会发生完全相同的事情,而不是我放置 HomePage 的位置,它会读取 CoursePage,反之亦然。
  • 我总是丢失 STEP 2 的 componentDidMount(第一次重定向)。 之后,所有 componentDidMount 函数按预期正常触发。
  • 注意第 3 步和第 4 步中的粗体部分是如何以相反的顺序触发的。我不确定这是否有任何意义。

问题

  • 为什么在 STEP 2 中 Route 的 component 没有触发其 componentDidMount 方法? 我在这里遗漏了一些非常明显的东西,是我不知道的一些神秘知识还是我遇到错误了吗?

  • 奖励:在CoursePagecomponentWillUnmount 之前触发HomePage 的构造函数是怎么回事,而当我们从@987654374 导航时,反面不是真的@到/courses/:coursName ?

documentation

当你使用组件(而不是渲染,如下)时,路由器使用 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


    【解决方案1】:

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

    【讨论】:

    • Page 组件仍然需要渲染它的子组件,所以需要children。无论如何,按照您的建议进行操作仍然会丢失第一个 componentDidMount :/
    • 感谢您的帮助。原来我的问题是特定于我自己的实现(阅读问题最底部的最终更新),如果不阅读SiteHeader 的实现,没有人能够弄清楚它。仍然会将其标记为已接受的答案并对其进行投票,以花时间。干杯。
    猜你喜欢
    • 1970-01-01
    • 2017-03-14
    • 2020-08-18
    • 1970-01-01
    • 2016-07-21
    • 2014-09-17
    • 1970-01-01
    • 2021-10-31
    • 2020-06-02
    相关资源
    最近更新 更多