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.