Next.js: Application Layout?

Created on 25 Oct 2016  路  10Comments  路  Source: vercel/next.js

In the React context, when building an app I'm used to the concept of containers and components. It appears to me that "pages" are somewhat equivalent to containers within next.js.

Is there a recommended way to add an application layout container such that I could specify for example global <Header/> and <Footer/> components with the router determining which content to display within (the page)? Similar to how the popular react-router package match function can be configured on the server.

Using the next.js default router and pages folder as is, to achieve this do I have no option but to duplicate <Header/> and <Footer/> across all pages?

Most helpful comment

Just an idea: you may consider to write an higher order component that takes your page component and returns some structure like this

<section>
   <Header />
   <YourPageComponent />
   <Footer />
</section>

Update:

components/AppLayout.js

import React, { Component } from 'react';
import { Header, Footer } from 'components';

const withAppLayout = () => (ComposedComponent) => {
  class AppLayout extends Component {
    render() {
      return (
        <section>
           <Header />
           <ComposedComponent {...this.props} />
           <Footer />
         </section>
      );
    }
  }

  return AppLayout;
};

export default withAppLayout;

pages/index.js

import withAppLayout from 'components/AppLayout';

const Home = () => (<div>Home</div>);

export default withAppLayout(Home);

All 10 comments

Just an idea: you may consider to write an higher order component that takes your page component and returns some structure like this

<section>
   <Header />
   <YourPageComponent />
   <Footer />
</section>

Update:

components/AppLayout.js

import React, { Component } from 'react';
import { Header, Footer } from 'components';

const withAppLayout = () => (ComposedComponent) => {
  class AppLayout extends Component {
    render() {
      return (
        <section>
           <Header />
           <ComposedComponent {...this.props} />
           <Footer />
         </section>
      );
    }
  }

  return AppLayout;
};

export default withAppLayout;

pages/index.js

import withAppLayout from 'components/AppLayout';

const Home = () => (<div>Home</div>);

export default withAppLayout(Home);

Thank you for your reply 馃槂 .

Where would I specify this HOC in the context of next.js though?

The default router will render index.js for / and about.js for /about. Do I have to duplicate for both?

index.js

export default () => (
  <div><Header/>Home<Footer/></div>
)

about.js

export default () => (
  <div><Header/>About<Footer/></div>
)

@davidrossjones one option is:

// components/Layout.js

export default () => (
  <div>
    <h1>Header</h1>
    {this.props.children}
    <footer>the footer</footer>
  </div>
)
// pages/index.js

import Layout from '../components/Layout'

export default () => (
  <Layout>
    <p>Home</p>
  </Layout>
)
// pages/about.js

import Layout from '../components/Layout'

export default () => (
  <Layout>
    <p>About</p>
  </Layout>
)

Aha! That makes perfect sense.

Thank you @altayaydemir and @impronunciable for the insight! Awesome. 馃憤

@impronunciable @altayaydemir Apparently, the Layout wrapper component gets re-mounted when changing routes which does not completely solve the problem. @ericf describes this in #50.

@dlindenkreuz well, you are right. 馃槬 I also agree on having an app layout component.

how to get initial props using this layout? like this

static getInitialProps ({ req}) {
  return {request: req ? 'Server' : 'Client '}
}

In the React context, when building an app I'm used to the concept of containers and components. It appears to me that "pages" are somewhat equivalent to containers within next.js.

I was wondering the same thing as well. Is there anything fundamentally different between pages and containers?

Wondering the same over here.

I was used more to.

./pages/Index.js

const IndexPage = ({ serverCall }) => (
 <div>
   <button onClick={serverCall}>Hello</button>
</div>
);

export default IndexPage;

And then on.

 ./containers/Index.is

import IndexPage from './pages/Index.js'

const composerData = (props, onData) => {
   onData(null, {
     serverCall: () => console.log('call');
   })
};
export default compose(composerData)(IndexPage);

where compose can be something like https://github.com/arunoda/react-komposer, but still i'm not sure if this the correct usage for NextJs, or i can avoid the Container and do this on the Page directly

You could use pages/_app.js for global layout now.

Was this page helpful?
0 / 5 - 0 ratings