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

Updated: