Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I only wrap some pages in a Context Provider with Next.js?

I have three pages that I want to share data between (these are the core of the web app) but I also have a bunch of blog pages that don't care about that data. Everywhere I've looked suggests putting the Provider in the _app.tsx file. If I understand that correctly if I wrapp MyApp with the provider, if someone goes straight to www.myurl.com/blog/my-blog-1 (from google), that will cause the provider to run its functions; even if that page won't call useContext

How do I only wrap three pages in the Provider and leave out the blog pages?

For example:

  • www.myurl.com -> I want this to use the shared data from the provider
  • www.myurl.com/my-functionality -> I want this to use the shared data from the provider
  • www.myurl.com/profile-> I want this to use the shared data from the provider
  • www.myurl.com/blog/* -> I don't want this to call the functions in the auth provider

Here's what my _app.tsx looks like:

import { AppProps } from 'next/app'
import '../styles/index.css'

export default function MyApp({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />
}
like image 476
mpc75 Avatar asked Nov 06 '20 21:11

mpc75


People also ask

What is getLayout in NextJS?

Per-Page Layouts If you need multiple layouts, you can add a property getLayout to your page, allowing you to return a React component for the layout. This allows you to define the layout on a per-page basis.

How do you set context in NextJS?

Wrap the entire app inside the AppContext.Provider In a Next. js app, we can see file _app. js inside the pages directory and, all the pages are rendered via this component. Here, we will import the AppContext file and languageObject we created earlier.

Can I use Usecontext in NextJS?

js. Starting from React v16. 3.0 , it is possible to use a new feature named context to pass data throughout the app.


2 Answers

A bit late to the party but there is actually an official way to do this: Use a per page layout. First slightly tweak your _app.tsx file:

import type { ReactElement, ReactNode } from 'react';
import { AppProps } from 'next/app';
import type { NextPage } from 'next';

type NextPageWithLayout = NextPage & {
    getLayout?: (page: ReactElement) => ReactNode;
};

type AppPropsWithLayout = AppProps & {
    Component: NextPageWithLayout;
};
export const App = ({ Component, pageProps }: AppPropsWithLayout): unknown => {

    // Use the custom layout defined at the page level, if available
    const getLayout = Component.getLayout ?? ((page) => page);

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

Then in a Page component write the following:

// DashboardPage.ts that need to have a UserProvider and CompanyProvider
import Layout from '@components/Layout'; // Default Layout that is imported for all the page
import { ReactElement } from 'react';
import { UserProvider } from '@contexts/user';
import { CompanyProvider } from '@contexts/company';

const DashboardPage = (): JSX.Element => {
    return <DashboardContainer />;
};

// Custom Layout to wrap the page within the User and company providers
DashboardPage.getLayout = function getLayout(page: ReactElement) {
    return (
        <Layout title="Dashboard page">
            <UserProvider>
                <CompanyProvider>{page}</CompanyProvider>
            </UserProvider>
        </Layout>
    );
};

export default DashboardPage;

like image 163
Mr Washington Avatar answered Sep 26 '22 02:09

Mr Washington


Well, this is an interesting issue.

Challenge is in the way Next implements file-based routing. Since there is no way to create a wrapper for the group of pages only out-of-the-box thing you can do is to wrap the App in the context providers. But that doesn't really resolve your issue.

SOOO... I think there is a workaround. If you want to be able to wrap a certain group of pages in the context provider, first, you need to replace the file-based router with the react-router.

There is a very interesting article on this topic by Andrea Carraro. I think you should try this out: https://dev.to/toomuchdesign/next-js-react-router-2kl8

I will try to find another solution as well, but let me know did this worked for you.

like image 23
Dejan Sandic Avatar answered Sep 23 '22 02:09

Dejan Sandic