3

不要费心阅读问题,最后有一个解决方案

我有以下路由器,使用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,HomePageCoursePage是纯表示组件;他们把道具吐出来。没有连接到 redux 商店或任何东西。HomePage并被CoursePage定义为类。

在里面HomePageCoursePage我需要使用componentDidMount钩子,以便与 DOM 交互。

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

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

  • Page执行的渲染函数
  • HomePageexecute的构造函数
  • componentDidMountofHomePage执行_

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

  • Page执行的渲染函数
  • componentWillUnmountofHomePage执行_
  • CoursePageexecute的构造函数

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

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

  • Page执行的渲染函数
  • HomePageexecute的构造函数
  • componentWillUnmountofCoursePage执行_
  • componentDidMountofHomePage执行_

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

  • Page执行的渲染函数
  • componentWillUnmountofHomePage执行_
  • CoursePageexecute的构造函数
  • componentDidMountofCoursePage执行_

笔记

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

问题

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

  • 奖励:在ofHomePage之前触发的构造函数是怎么回事,而当我们从to导航时,相反的不是真的?componentWillUnmountCoursePage//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感谢任何打扰阅读我的胡言乱语并抱歉浪费您时间的人。

4

1 回答 1

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>
    );
  }
}
于 2017-04-18T14:36:29.787 回答