React Router v4 with Multiple Layouts
We will use React to build a very simple app with two layouts, login layout and app layout.
Installing Crate React APP
To get React projects up and running quickly with Create React App, get a look the previous chapter.
Installing React Router Dom
Open up your terminal and run:
npm install --save react-router-dom
Creating the Layout
React router offers a render prop which will be called when the route matches:
// Using the render prop allows a more manual setup
<Route path="/" render={matchProps => <SomeComponent {...matchProps} />} />
This is useful because we can wrap a component around the <Route /> and control where our component is rendered whilst allowing all the usual props to be Route get passed through:
// Login layout
const LoginLayout = ({ children }) => (
<div>
<p>Login Layout</p>
{children}
</div>
);
const LoginLayoutRoute = ({component: Component, ...rest}) => {
return (
<Route {...rest} render={matchProps => (
<LoginLayout>
<Component {...matchProps} />
</LoginLayout>
)} />
)
};
// App layout
const AppLayout = ({ children }) => (
<div>
<p>App Layout</p>
{children}
</div>
);
const AppLayoutRoute = ({component: Component, ...rest}) => {
return (
<Route {...rest} render={matchProps => (
<AppLayout>
<Component {...matchProps} />
</AppLayout>
)} />
)
};
The rest parameter will contain every prop passed to LoginLayoutRoute except component so it allows us to forward them on to the underlying Route component as usual.
Providing a render prop to the Route we can control where the component prop is rendered. In this case we wrap it in AppLayout component as a children. The matchProps are what usually get passed to a component rendered by Route.
Implementing the Layout
Now, we will add routes to the app. Instead of rendering App element.
App.js
import React from 'react';
import { BrowserRouter, Route, Redirect, Switch, Link } from 'react-router-dom';
// Login layout
const LoginLayout = ({ children }) => (
<div>
<p>Login Layout</p>
{children}
</div>
);
const LoginLayoutRoute = ({component: Component, ...rest}) => {
return (
<Route {...rest} render={matchProps => (
<LoginLayout>
<Component {...matchProps} />
</LoginLayout>
)} />
)
};
// App layout
const AppLayout = ({ children }) => (
<div>
<p>App Layout</p>
<br/>
<ul>
<li><Link to={'/homes'}>Home</Link></li>
<li><Link to={'/users'}>User</Link></li>
</ul>
{children}
</div>
);
const AppLayoutRoute = ({component: Component, ...rest}) => {
return (
<Route {...rest} render={matchProps => (
<AppLayout>
<Component {...matchProps} />
</AppLayout>
)} />
)
};
// Pages
const LoginPage = ({ classes }) => {
return (
<div>
Login Page
</div>
);
};
const HomePage = ({ classes }) => {
return (
<div>
Home Page
</div>
);
};
const UserPage = ({ classes }) => {
return (
<div>
User Page
</div>
);
};
export default (
<BrowserRouter>
<Switch>
<Route exact path="/">
<Redirect to="/signin" />
</Route>
<LoginLayoutRoute path="/signin" component={LoginPage} />
<AppLayoutRoute path="/homes" component={HomePage} />
<AppLayoutRoute path="/users" component={UserPage} />
</Switch>
</BrowserRouter>
);