0

Can you please help me move the next-redux-wrapper store provider into a layout component?

My current codes follows the next-redux-wrapper office docs and it works fine, but I would like to move the store provider into a layout component in case where the Redux store provider isn't required as it might just be a plain page.

When I tried to move it to a layout component, I'm not able to access the pageProps as props is now a jsx element. But the parent pageProps is required by next-redux-wrapper.

I don't really know how to do this. How do I get the original parent pageProps in the layout component?

Here is my working version:

//_app.tsx

import { NextPage } from "next";
import type { AppProps } from "next/app";
import { ReactElement, ReactNode } from "react";
import { Provider } from "react-redux";
import { wrapper } from "../../lib/redux/store/store";
import "../../styles/globals.css";

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

type AppPropsWithLayout = AppProps & {
  Component: NextPageWithLayoutAndAuth;
};

function MyApp({ Component, pageProps }: AppPropsWithLayout) {
  const getLayout = Component.getLayout || ((page) => page);

  const { store, props } = wrapper.useWrappedStore(pageProps);  // <---- Move this to Layout Component

  return getLayout(
    <Provider store={store}>                                    // <---- Move this to Layout Component
      <Component {...props.pageProps} />
    </Provider>                                                 // <---- Move this to Layout Component
  );
}

export default MyApp;
//withLayout.tsx

import AuthLayout from "../components/auth/AuthLayout";
import AuthReduxLayout from "../components/auth/AuthReduxLayout";
import DefaultLayout from "../components/auth/DefaultLayout";

type LayoutType = "default" | "auth" | "authRedux";

export default function withLayout(layoutType: LayoutType, title: string) {
  if (layoutType === "auth") {
    return function getLayout(page: React.ReactElement) {
      return <AuthLayout title={title}>{page}</AuthLayout>;
    };
  }

  if (layoutType === "authRedux") {
    return function getLayout(page: React.ReactElement) {
      return <AuthReduxLayout title={title}>{page}</AuthReduxLayout>;
    };
  }

  return function getLayout(page: React.ReactElement) {
    return <DefaultLayout title={title}>{page}</DefaultLayout>;
  };
}
//AuthReduxLayout.tsx

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import { Fragment } from "react";
import Footer from "../../../src/components/layout/footer";
import Header from "../../../src/components/layout/header";

const queryClient = new QueryClient();

const AuthReduxLayout = (props: any) => {
  // const { store, props } = wrapper.useWrappedStore(pageProps);   //<--- Move to here

  return (
    <QueryClientProvider client={queryClient}>
      {/* <Provider store={store}>                                  //<--- Move to here     */}
      <Fragment>
        <Header />
        <main>{props.children}</main>
        <Footer />
      </Fragment>
      {/* </Provider>                                               //<--- Move to here     */}
      <ReactQueryDevtools initialIsOpen={false} />
    </QueryClientProvider>
  );
};

export default AuthReduxLayout;

I tried to access the parent pageProps using React.Children and then apply the next-redux-wrapper's useWrappedStore hook to access the required props, but it doesn't work.

//AuthReduxLayout.tsx (testing version)

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import React, { Fragment } from "react";
import { Provider } from "react-redux";
import Footer from "../../../src/components/layout/footer";
import Header from "../../../src/components/layout/header";
import { wrapper } from "../../redux/store/store";

const queryClient = new QueryClient();

const AuthReduxLayout = (parentProps: any) => {

  const { store, props } = wrapper.useWrappedStore(parentProps);


  const updatedChildren = (pobjProps:any) => {
    
    return React.Children.map(parentProps.children,(child)=> React.cloneElement(child,{ ...pobjProps }))
  }

  const newChildren = updatedChildren(props);



  return (
    <QueryClientProvider client={queryClient}>
      <Provider store={store}>
      <Fragment>
        <Header />
        <main>{newChildren}</main>
        <Footer />
      </Fragment>
      </Provider>
      <ReactQueryDevtools initialIsOpen={false} />
    </QueryClientProvider>
  );
};

export default AuthReduxLayout;

Any clues would be appreciated. Thanks

Mav33rick
  • 21
  • 5

1 Answers1

1

I figured it out. I had to pass the page.props in the withLayout hoc as a property of the component.

if (layoutType === "authRedux") {
    return function getLayout(page: React.ReactElement) {
      return (
        <AuthReduxLayout title={title} pageProps={page.props}>
          {page}
        </AuthReduxLayout>
      );
    };
  }

Then I am able to access that property in the child component like this:

const AuthReduxLayout = (parentProps: any) => {
  const { store, props } = wrapper.useWrappedStore(parentProps.pageProps);

  return (
    <QueryClientProvider client={queryClient}>
      <Provider store={store}>
        <Fragment>
          <Header />
          <main>{props.children}</main>
          <Footer />
        </Fragment>
      </Provider>
      <ReactQueryDevtools initialIsOpen={false} />
    </QueryClientProvider>
  );
};
Mav33rick
  • 21
  • 5