I'd like to define the following structure on my page:
Where layout is static and contains elements that appear on every page, and render page content based on the URL.
To achieve this I've defined AppRoutes, Layout, About and NotFound and used react-router, v4:
AppRoutes.js
export default class AppRoutes extends React.Component
{
render ()
{
const supportsHistory = 'pushState' in window.history;
return (
<BrowserRouter forceRefresh={!supportsHistory} history={hashHistory} onUpdate={() => window.scrollTo(0, 0)}>
<div>
<Route path='/' component={Layout}>
<Route path='/about' component={About}/>
<Route path='*' component={PageNotFround}/>
</Route>
</div>
</BrowserRouter>);
};
};
Layout.js
class NaviGationPane extends React.Component
{
render()
{
return (
<div>
<NavLink to="/">Home</NavLink>
<NavLink to="/about">About</NavLink>
</div>
)
}
}
export default class Layout extends React.Component
{
render ()
{
return (
<div className="app-container">
<header>
<NaviGationPane/>
</header>
<div className="app-content">
{this.props.children}
</div>
</div>
);
}
}
Layout's header is rendered, but at / or at /about the page content is empty.
If I change it to the one below the PageNotFound is rendered always at the end, no matter what is the path, while the rest works as I expected, namely / renders he Layout, while /about renders the About component.
<BrowserRouter forceRefresh={!supportsHistory} history={hashHistory} onUpdate={() => window.scrollTo(0, 0)}>
<div>
<Route path='/' component={Layout}/>
<Route path='/about' component={About}/>
<Route path='*' component={PageNotFround}/>
</div>
</BrowserRouter>
I checked that in both cases this.props.children in Layout is undefined.
UPDATE I tried out a few things and figured that
<Layout>
<Switch>
<Route exact path='/' component={IndexPage}/>
<Route path='/about' component={About}/>
<Route component={PageNotFround}/>
</Switch>
</Layout>
will be the basic scenario and now I understand why my previous code did not work: in react-router v4 the
<Route to='/' component={Layout}>
<Route path='/about' component={About}/>
</Route>
is not valid. The structure
<BrowserRouter>
<div>
<Route path='/' component={Layout}>
<Route path='/about' component={About}/>
<Route path='*' component={PageNotFround}/>
</div>
</BrowserRouter>
will keep matching routes until all rules are exhausted, the / will be matched every time and * will also be matched every time.
So I use the <Layout> component to wrap everything and create the routes inside and to ensure that only one path is matched I use the <Switch>.
This is not what I wanted, because if I add a path /about/:user only the About component will be rendered. So the question is still open.
