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