Layout Persistence in Next.js
Tags: nextjs, react, javascript, webdev
Published: 2020-06-15 10:34:26

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 to the top doesn't mean that the navbar wouldn't be unmounted when the user is directed to another page. For **SPAs** (Single Page Application), it's the expected behaviour that the navbar remains mounted throughout the routing. While it's easy to achieve this on **CRA** (Create React App), it can be difficult to maintain layout persistence in **Gatsby** or **Next.js**, since routing is different due to code-splitting. In this post, we will ensure the persistence of the layout component during page transitions **without using any library** in Next.js.

First of all, if it isn't already added, we need to add an **“_app.js”** file under **”/ pages”**. In this way, we will be able to interfere with the initializing process of the application, and will be able to contain the page component in the layout component we will be creating soon. In its simplest form, an **“_app.js”** file looks like this:

```javascript
export default function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}
```

This is where we'll be adding layout support for our app. Let’s change the **“_app.js”** file we created under **“/ pages”** as follows:

```javascript
import React from "react";

export default function MyApp({ Component, pageProps }) {
  const Layout = Component.Layout ? Component.Layout : React.Fragment;

  return (
    <Layout>
      <Component {...pageProps} />
    </Layout>
  )
}
```

**Component** here is the component that returns for the URL path you are on. For example; if you are on the homepage, the default export from **“/pages/index.js”** will return here. Therefore, we'll be adding layout components we created directly to the page components. We’ll get back to that later. Let’s create our layout. We can create it under **“/layouts/MyLayout.js”** to keep the project tidy:

```javascript
import React, { useState } from "react";

export default function MyLayout({ children }) {
  const [counter, setCounter] = useState(0);
  
  return (
    <>
      <p>      
        <button onClick={() => setCounter(counter + 1)}>
          Clicked {counter} Times
        </button>
      </p>

      {children}
    </>
  )
}
```

If we were able to achieve layout persistance with the voodoo we cast in **“pages / _app.js”**, the number shown by the button with the counter on it shouldn't reset during routing. So, let’s create two sample pages under the **“pages”** folder to test this. First, **“/pages/profile.js”**:

```javascript
import Link from "next/link";

export default function Profile() {
  return (
    <div>
      <p>This is the Profile page.</p>
      <p>
        <Link href="/account">
          <a>Go: Account</a>
        </Link>
      </p>
    </div>
  );
}
```

So, how do we add the layout component we just created to this page component? As I mentioned before; directly…

```javascript
import Link from "next/link";
import MyLayout from "../layouts/MyLayout";

export default function Profile() {
  return (
    <div>
      <p>This is the Profile page.</p>
      <p>
        <Link href="/account">
          <a>Go: Account</a>
        </Link>
      </p>
    </div>
  );
}

Profile.Layout = MyLayout;
```

Well, this is not even slightly complicated. Let’s continue by adding our second sample page under **“/pages/account.js”**:

```javascript
import MyLayout from "../layouts/MyLayout";

export default function Account() {
  return (
    <div>
      <p>This is the Account page.</p>
      <p>
        <Link href="/profile">
          <a>Go: Profile</a>
        </Link>
      </p>
    </div>
  );
}

Account.Layout = MyLayout;
```

All preparations have been completed. Now I'll open the **Profile** page in the browser for you. And I'll click the button with the counter on it for **4 times**. Then I'll go to the **Account** page, and the result will be:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/y3kc8w96vsjzjinu5f5r.png)

The counter didn't reset during routing because these two pages share the same layout component. If I go to a different page, **MyLayout** will be unmounted and the counter will reset.

In this way, you can keep navigation elements like **Tab Bars** etc. persistent across pages. Or, you can go to the kitchen and bake a strawberry cake, I don’t know, I’m ending this post.

---

I hope this was useful, you can also follow me on Twitter for future content:

[twitter.com/ozanbll](https://twitter.com/ozanbll)