DEV Community

Cover image for Layout Persistence in Next.js

Layout Persistence in Next.js

Ozan Bolel on June 15, 2020

Although the word layout is generally related to CSS page layout, the reason why I’m posting this is a bit different. Fixing the position of navbar...
Collapse
 
leowasabee profile image
Léo Stewart

Hi,
I wonder why do you bother to import MyLayout in every pages when just import MyLayout in the _app work the same, without this MyPage.Layout = MyLayout; ?
I hav checkd and id works as expected and in a simplier way.
Leo

Collapse
 
ozanbolel profile image
Ozan Bolel • Edited

To have multiple layouts within the app. We wouldn't want all pages to share the same layout.

Collapse
 
leowasabee profile image
Léo Stewart • Edited

Oh ! That make sense. Maybe it could be easier with a custom hook then ?
Like :

import { useState } from "react";

const FirstLayout = ({ children }) => {
  const [counter, setCounter] = useState(0);

  return (
    <>
      <p> First Layout     
        <button onClick={() => setCounter(counter + 1)}>
          Clicked {counter} Times
        </button>
      </p>

      {children}
    </>
  )
}

export default FirstLayout

export function withFirstLayout (Component){
  Component.Layout = FirstLayout
  return Component
}
Enter fullscreen mode Exit fullscreen mode

and the page :

import { withFirstLayout } from 'layout/FirstLayout'

const Home = () => {
  return  <div>  index   </div>
}
export default withFirstLayout(Home)
Enter fullscreen mode Exit fullscreen mode

But when we change the layout we still have a reset of the old one

Collapse
 
thomas159 profile image
thomas159

how can I update the title in the head using this layout?

Collapse
 
ozanbolel profile image
Ozan Bolel • Edited

Don't. Use title inside Head from next/head instead.

Collapse
 
ramirezsandin profile image
Jorge • Edited

Hi, do you mean to use the Head tag and title tag inside every page?

Would it be possible to have the Head tag in the layout component and pass the title variable somehow when you are doing Page.Layout = MyLayout?

Thread Thread
 
ozanbolel profile image
Ozan Bolel • Edited

Yes I meant that.

It is possible but it adds an unnecessary complexity imho.

Thread Thread
 
joshuatuscan profile image
Joshua Tuscan

What if you want to pass a prop to the MyLayout so that you can let your nav component know what page you are on? How do you pass props to MyLayout?

Collapse
 
iigorcunha profile image
Igor Cunha

Any idea, how to implement Layout with typescript?

Collapse
 
ozanbolel profile image
Ozan Bolel
import * as React from "react";
import { NextPage } from "next";

type Page = NextPage & { Layout?: React.FC };
Enter fullscreen mode Exit fullscreen mode
Collapse
 
iigorcunha profile image
Igor Cunha

Thanks, I was blowing my mind trying to figure that.

Thread Thread
 
pikeas profile image
Aris Pikeas

Could you share a bit more context on how you got this working with Typescript?Component.layout is throwing "unsafe assignment of an any value".

Thread Thread
 
ozanbolel profile image
Ozan Bolel
import * as React from "react";
import { NextPage } from "next";

type Page = NextPage & { Layout?: React.FC };

const MyPageComponent: Page = () => {
  return null;
}

export default MyPageComponent;
Thread Thread
 
pikeas profile image
Aris Pikeas
type Page = NextPage & {
    layout?: (props: { children: ReactNode }) => JSX.Element
}
Enter fullscreen mode Exit fullscreen mode

This seems to have done the trick for me when not using fat-arrow functions.

Collapse
 
macgyver98 profile image
MacGyver98

Hi! thanks for your effort and share us.

What about if I need to decide between two different layouts? Where should I put the logic and how should I export Layout from my page?

Collapse
 
nerdherd profile image
ali • Edited

You will assign the layout to the page in the page file.

Upon navigating to a page, _app.js will render the layout from the page component via Component.Layout as per the authors code.

// pages/home.js
import HomeLayout from '../layouts/home-layout.jsx

const HomePage = () => (
   <div>HomePage</div>
)

// assigning HomeLayout to the page property `Layout`
HomePage.Layout = HomeLayout

export default HomePage
Enter fullscreen mode Exit fullscreen mode
// pages/account.js
import AccountLayout from '../layouts/account-layout.jsx
const AccountPage = () => (
   <div>Account Page</div> 
)

AccountPage.Layout = AccountLayout

export default AccountPage
Enter fullscreen mode Exit fullscreen mode