30

How to not wrap a specific page with Layout component in _app.js?

For example, I have two pages as pages/home and pages/about, now how can I not wrap my pages/home page with Layout component?

pages/_app.js

import "../styles/globals.css";
import Layout from "../components/Layout";

function MyApp({ Component, pageProps }) {

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

export default MyApp;

What I have tried:

pages/_app.js

function MyApp({ Component, pageProps }) {
  console.log(typeof Component); // gives me a function

  switch (Component) {
    case Home():
      return <Component {...pageProps} />;
    default:
      return (
        <Layout>
          <Component {...pageProps} />{" "}
        </Layout>
      );
  }
}

pages/home.js

import React from 'react';
 
const Home= () => {
  return (<div>Hello</div>);
};
 
export default Home;
Shreyas Jadhav
  • 2,363
  • 4
  • 10
  • 23

8 Answers8

40

by checking the appProps.router.pathname property passed to it.

way 1

function MyApp({ Component, pageProps, ...appProps }: AppProps) {

  // make function that will return the children based on router.pathname

  const getContent = () => {
    // array of all the paths that doesn't need layout
    if ([`/dashboard`].includes(appProps.router.pathname))
      return <Component {...pageProps} />;

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

  return <ApplicationWrapper>{getContent()}</ApplicationWrapper>;
}

way 2

function MyApp({ Component, pageProps, ...appProps }: AppProps) {
  
  // use a LayoutComponent variable 
  // that switches to actual Layout or React.Fragment (no layout) 
  // accordingly to pathname

  const isLayoutNeeded = [`/dashboard`].includes(appProps.router.pathname);
  const LayoutComponent = isLayoutNeeded ? Layout : React.Fragment;

  return (
    <ApplicationWrapper> 
      <LayoutComponent>
        <Component />
      </LayoutCompnent>
    </ApplicationWrapper>
  );
}

TIP:

you can use path.startsWith to check all the paths, example

if(router.pathname.startsWith(`/dashboard`))
Gaslan
  • 808
  • 1
  • 20
  • 27
Shreyas Jadhav
  • 2,363
  • 4
  • 10
  • 23
27

I think there is cleaner way of doing this with Per-Page Layouts. I'm currently doing this simple by creating a default layout for all pages and override it for the pages that require specific layout, for example in my login and registration pages.

    export default function LoginPage() {
      return {
        /** Some JSX */
      }
    }
    // Return the page without additional layout.
    LoginPage.getLayout = (page) => page

    export default function MyApp({ Component, pageProps }) {
      // Use the specified page layout or fallback to the default one.
      const getLayout = Component.getLayout ?? defaultPageLayout

      return getLayout(<Component {...pageProps} />)
    }
Ivan Nakov
  • 414
  • 6
  • 9
2

I use displayName static property. It works in any React.js component as well.

const OGImagePreview = () => <h1>OG Image Preview</h1>

OGImagePreview.displayName = 'OGImagePreview'

export default OGImagePreview

Then I use switch...case in _app.tsx like:

switch (Component.displayName) {
    case 'OGImagePreview':
        return (
            <>
                <Component {...pageProps} />
            </>
        )
    default:
        return (
            <>
                <Head>
                    <meta name="viewport" content="initial-scale=1.0, width=device-width" />
                </Head>
                <ThemeProvider attribute="class" themes={['light', 'dark']}>
                    <Progress />
                    <Nav />
                    <Component {...pageProps} />
                </ThemeProvider>
                <ScrollToTop />
                <Analytics />
            </>
        )
}
deadcoder0904
  • 7,232
  • 12
  • 66
  • 163
2

what about this? Hope can save someone

import "../styles/globals.css";
import dynamic from "next/dynamic";
const Layout = dynamic(() => import("@layout/Layout"));
import { useRouter } from "next/router";

function MyApp({ Component, pageProps }) {
  const router = useRouter();
  return (
    <>
      {router.pathname !== "/" ? (
        <Layout>
          <Component {...pageProps} />
        </Layout>
      ) : (
        <Component {...pageProps} />
      )}
    </>
  );
}

export default MyApp;
2

You can simply leverage useRouter from 'next/router' and get your job done easily.

import {useRouter} from 'next/router';

function MyApp({ Component, pageProps }) {
  const router = useRouter();

  if(router.asPath =='/dashboard')  {
     return (
       <Component {...pageProps} />
     )
  }

 return (
   <Layout>
     <Component {...pageProps} />
   </Layout>
 );
 }
Tushar Hasan
  • 55
  • 1
  • 1
  • 6
1

What about using higher order components . They are not part of react API but as react docs says, "They are a pattern that emerges from React’s compositional nature." Next uses react so it does make sense to use react patterns in next

The following code wraps a given component with a predefined Header and Footer component. Then a component that uses it is wrapped with the HOC when exported

    const withLayout = Comp =>  {
        const WrappedComp = (props) => {
            return (
                <div id='layout'>
                    <Header />
                    <Comp {...props} />
                    <Footer />
                </div>
            );
        }
        return WrappedComp;
    }

    const Section = () => {
        return ( 
            <section>
                Section content...
            </section>
        );
    }

    export default withLayout(Section);
newbie
  • 126
  • 5
1

I have tried my code in this way and its working fine for me.

`
    import { useRouter } from "next/router";
    function MyApp({ Component, pageProps}: AppProps) {
      const router = useRouter();
      return (
        <>
          {router.pathname !== "/contact" ? (
            <>
              <NavBar />
              <Component {...pageProps} />
              <JoinUsSection />
              <Footer />
            </>
          ) : (
            <>
              <NavBar />
              <Component {...pageProps} />
              <Footer />
            </>
          )}
        </>
      );

}`
-1

When i use

class MyProfile extends React.Component {

    static noLayout = true;

    constructor(props){
        super(props);


    }
    render()
    {
        return (
            <a href="/test">test </a>

    )
}


 export default withRouter (connect(mapStateToProps, mapDispatchToProps)(MyProfile));

The static Variable noLayout is not accesible in _app.jsx

Component.noLayout.  // is undefined

Is undefined.

No way to "inject" static variable or props to determine which layout to use.

(maybe i can only use the router object)
When i look into:

console.log("Component:", Component);
console.log("Component props :", this.props);
console.log("Component page props :", pageProps);

enter image description here

So only what i see is this.props.router

if (this.props.router.pathname == "/ja/profil")
{
    return <Component {...pageProps} />;
}

Is there any better way?

Mike Rehy
  • 17
  • 2
  • If you have a new question, please ask it by clicking the [Ask Question](https://stackoverflow.com/questions/ask) button. Include a link to this question if it helps provide context. - [From Review](/review/late-answers/34052750) – ruud Mar 23 '23 at 11:57