loading...

Variable Page Layouts in React

dhintz89 profile image Daniel Hintz Updated on ・3 min read

Last week I explained how to get a constant Header-Content-Footer format for your React website. But now suppose you want a constant header almost all the time, but not quite all the time. Or you want additional components, like a side-bar, included on parts of your site. The solution I went through last week won't work well for these scenarios because there's no flexibility. Don't worry, we can still use the same concepts, but they will need to be extracted into another component, a Layout, to provide additional flexibility.

The Layout

In its simplest form, all we're doing is taking the Header and Footer out of index.js and adding them into a new file, Layout.js, instead.

// Layout.js
import React from 'react';
import Header from './Header';
import Footer from './Footer';

  const Layout = props => {
    return (
      <div>
        <Header/>
          {props.children}
        <Footer/>
      </div>
    );
  }

  export default Layout;
Enter fullscreen mode Exit fullscreen mode

Then, in the component that the Router renders, we wrap everything in the return statement inside of the Layout component:

// Main.js
import React, {Component} from 'react';
import Layout from './Layout';

export default class Main extends Component {
  render() {
    return (
      <Layout>
        <div className="Main">
          <h2>Hi There! I'm Dan Hintz and I'm a full-stack web developer.</h2>
        </div>
      </Layout>
    )
  }
}
Enter fullscreen mode Exit fullscreen mode

This causes the {props.children} line in Layout.js to display everything rendered by the Main Component in its place, which brings us to the exact same place as last week, although we'll need to add that Layout component into every router-displayed Component.

So what gives? That sounds tedious, so why would we want to do that? Well, with a little bit of extra work, we can set it up so that we can pass props from each Component and use them to customize the Layout as needed. Say for example, we want the header to display for every page except for our blog. How would we do that?

First, we'll need to pass a prop from each Component to the Layout. We'll call the prop 'displayHeader'. In the above code in Main.js, just change <Layout> to <Layout displayHeader={true}> to pass the prop. We'll need to do that for About.js too. For Blog.js; however, we'll need to change it to <Layout displayHeader={false}> since we don't want the header to display on this page.

Next we will go into Layout.js to use this passed in data. What we're trying to do here is express: "if the displayHeader prop is true, display Header; otherwise don't display anything" so all we need is a simple if statement. Unfortunately, since we use JSX in React, "if" won't work. Instead we use this format (the && represents an inline if:

{argument &&
  <RenderedComponent/>
}
Enter fullscreen mode Exit fullscreen mode

So now our Layout Component looks like this:

const Layout = props => {
    return (
      <div>
        {/* Remember: && is an inline if statement */}
        {props.displayHeader &&
          <Header/>
        }
          {props.children}
          {/* anything else you want on the Layout */}
        <Footer/>
      </div>
    );
  }

export default Layout;
Enter fullscreen mode Exit fullscreen mode

With that, since we are passing displayHeader=true for every Component except for Blog, we will now have a site that displays the Header for every page except the Blog page. How cool is that? Keep in mind that our NavLinks are located as part of our Header in this hypothetical case, so they will disappear in the Blog page.

Discussion

pic
Editor guide