next.js how to manage global state with context in across multiple layouts

2k Views Asked by At

I'm using two layouts in next.js in accordance with per page layout structure.

  • One layout for unauthenticated pages
  • Another one for authenticated pages

in _app.js

import GlobalContext from "../utils/GlobalContext";
....
return getLayout(
    <Layout>
      <Component {...pageProps} />
    </Layout>
);

in page

Login.getLayout = function getLayout(page) {
    return (
        <Layout2>
            {page}
        </Layout2>
    )
}

global state seems to be reset when visiting a page with different layout.

problem is how to keep global state shared though the context on multiple layouts?

3

There are 3 best solutions below

0
On BEST ANSWER

To share the global state shared among multiple templates we need to wrap the getLayout itself as below

in _app.js

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

Not sure if there is merit in two completely separate shared layouts but will try to address your question. I would create a shared context and single layout factory that returns the relevant layout based on your rule i.e. user exists etc.

Wrap your Layout in your Context in your _app.js:

function MyApp({ Component, pageProps, router }: MyAppProps) {
  return (
    <UserProvider>
      <Layout>
        <Component {...pageProps} key={router.asPath} />
      </Layout>
    </UserProvider>
  );
}

Then access context in Layout and render appropriate options:

// context
import { useUser } from '../utils/user';

import Header from './header';
import AuthenticatedHeader from './header/authenticated';

interface LayoutProps {
  children: any;
}

const DefaultLayout = ({ children }: LayoutProps) => {
  return (
    <>
      <Header />
      {children}
    </>
  );
};

const AuthLayout = ({ children }: LayoutProps) => {
  return (
    <>
      <AuthenticatedHeader />
      {children}
    </>
  );
};

const Layout = ({ children }: LayoutProps) => {
  const { user } = useUser();

  return (
    <>
      {/* conditionally render appropriate  */}
      {user ? <AuthLayout>{children}</AuthLayout> : <DefaultLayout>{children}</DefaultLayout>}
    </>
  );
};

export default Layout;

Codesandbox

0
On

In 'my' case... i solved like this in _app.js

i place getLayout() in context provider.

const getLayout = Component.getLayout || ((page) => page)
return (
  <LoginContext.Provider value={value}>
    <DataContext.Provider value={value2}>
      {getLayout(
        <Component {...pageProps} />
      )}
    </DataContext.Provider>
  </LoginContext.Provider>
)