Provided component in Route does not fire componentDidMount

DO NOT READ THE QUESTION, SOLUTION AT THE END

I have the following Router using Reactive Router 4

return (
  <Router>
    <Page>
      <Route exact path="/" component={HomePage} />
      <Route path="/courses/:courseName" component={CoursePage} />
    </Page>
  </Router>
);

      

The component Page

looks like this:

function Page(props) {
  const { children } = props;
  return (
    <div className="page">
      <SiteHeader />
      {children}
      <SiteFooter />
    </div>
  );
}

      

SiteHeader

, SiteFooter

, HomePage

And CoursePage

are net presentation components; they take props in their wiring. Not connected to reducer magazine or anything else. HomePage

and are CoursePage

defined as classes.

Internally HomePage

and CoursePage

I need to use a hook componentDidMount

to interact with the DOM.

Now the following strange thing happens:

STEP 1 : I reload the app from /

url

  • The render function Page

    does
  • The constructor function HomePage

    does
  • componentDidMount

    from HomePage

    performs

STEP 2 : I go to/courses/:courseName

  • The render function Page

    does
  • componentWillUnmount

    from HomePage

    performs
  • The constructor function CoursePage

    does

Note that it componentDidMount

CoursePage

doesn't work
. This is important because I need a componentDidMount

hook.

STEP 3 : I return to /

from/courses/:courseName

  • The render function Page

    does
  • The constructor function HomePage

    does
  • componentWillUnmount

    CoursePage

    performs
  • componentDidMount

    from HomePage

    performs

STEP 4 : back to /courses/:courseName

out again/

  • The render function Page

    does
  • componentWillUnmount

    of HomePage

    performs
  • The constructor function CoursePage

    does
  • componentDidMount

    CoursePage

    performs

NOTES

  • The same will happen if in STEP 1 I rebooted from /courses/:courseName

    instead /

    , instead of where I put it HomePage

    , it would read CoursePage

    and vice versa.
  • I always lose componentDidMount

    out of STEP 2 (first redirect).
    After that, all functions componentDidMount

    run normally as expected.
  • Notice how the highlighted items in steps 3 and 4 are fired in reverse order. I'm not sure if this matters.

QUESTIONS

  • Why component

    doesn't a route run its method in STEP 2 componentDidMount

    ?
    ... I am missing something very obvious here, is this some kind of secret knowledge that I am not aware of or am I hitting a bug?

  • Bonus: what's the deal with the constructor's HomePage

    trigger function before componentWillUnmount

    CoursePage

    , while oposite doesn't match true when we move from /

    to /courses/:coursName

    ?

Per documentation

When using a component (instead of rendering below), the router uses React.createElement to create a new React element from the given component. This means that if you provide a built-in function, you are creating a new component for each render. This causes the components to be unmounted and the new component is installed instead of updating the existing component.

which makes my problem even less tangible.

BEGINNING OF WORK

In my component Page

if I just move the order children

like this

function Page(props) {
  const { children } = props;
  return (
    <div className="page">
      {children} // MOVED FIRST
      <SiteHeader />
      <SiteFooter />
    </div>
  );
}

      

then the problem will be solved, however I don't think this is the correct solution. I'd love to know what's going on because it's tearing me apart.

EDIT:

The question has been edited for brevity and to simplify the usecase

UPDATE - FURTHER OBSERVATIONS

Let be the Stub.jsx

next component

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;

      

and MockPage.jsx

- next component

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

      

Then all of the following configurations are played correctly, means there are no calls componentDidMount

between redirects
:

AND)

return (
  <Router>
    <div>
      <Route exact path="/" component={Stub} />
      <Route path="/courses/:courseName" component={Stub} />
    </div>
  </Router>
);

      

IN)

return (
  <Router>
    <MockPage>
      <Route exact path="/" component={Stub} />
      <Route path="/courses/:courseName" component={Stub} />
    </MockPage>
  </Router>
);

      

FINAL UPDATE:

FIND THE PROBLEM!

The problem was apparently in react-addon-perf

which I was using inside the button which I was importing into my component SiteHeader

. The Perf tool threw an error on the first redirect that occurred, which messed up the lifecycle hooks of subsequent components. This explains the fact that when I moved the position children

to SiteHeader

, everything worked. Thanks to everyone who worried about reading my hoarseness and apologize for wasting your time.

+3


source to share


1 answer


With React-route 4 you can compose pages like this. Each route corresponding to the route will be shown in the view. Props are no longer needed with React-route 4.

This code works for me. If I navigate to '/' the title, start page and footer are displayed including DidMount. If I go to "/ courses / 1" then the title, main page, course and footer will be displayed including 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>
    );
  }
}

      

+1


source







All Articles