简体   繁体   中英

Next.js Opt out of Layout Component for specific pages from _app.js

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;

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

way 1

function MyApp({ Component, pageProps, ...appProps }: AppProps) {
  const getContent = () => {
    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) {

    const isLayoutNeeded = [`/dashboard`].includes(appProps.router.pathname);

    const LayoutComponent = isLayoutNeeded ? Layout : React.Fragment;

    


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

I think there is cleaner way of doing this withPer-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} />)
    }

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 />
            </>
        )
}

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;

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>
 );
 }

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);

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 />
            </>
          )}
        </>
      );

}`

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM