Reputation: 2571
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;
Upvotes: 33
Views: 37184
Reputation: 2571
by checking the appProps.router.pathname
property passed to it.
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>;
}
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`))
Upvotes: 43
Reputation: 17
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);
So only what i see is this.props.router
if (this.props.router.pathname == "/ja/profil")
{
return <Component {...pageProps} />;
}
Is there any better way?
Upvotes: -1
Reputation: 21
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 />
</>
)}
</>
);
}`
Upvotes: 1
Reputation: 146
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);
Upvotes: 1
Reputation: 55
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>
);
}
Upvotes: 2
Reputation: 31
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;
Upvotes: 3
Reputation: 444
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} />)
}
Upvotes: 30
Reputation: 8693
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 />
</>
)
}
Upvotes: 2