I am having issues with wrapPageElement
in my Gatsby 4 project.
wrapPageElement.js
import React from 'react';
import { PathProvider } from './src/providers/path';
import Layout from './src/components/layout/layout';
// Pass all props (hence the ...props)
// to the layout component so it has access to things like pageContext or location
const wrapPageElement = ({ element, props: { location } }) => (
<PathProvider path={location.pathname}>
<Layout>{element}</Layout>
</PathProvider>
);
export default wrapPageElement;
I am using wrapPageElement
to reuse my Layout across all pages but the Layout does not update its React state properly when included via wrapPageElement. If I render Layout within my pages instead, it works fine.
gatsby-brower.js
import './src/styles/global.css';
import CustomProviders from './wrapWithProvider';
import CustomLayout from './wrapPageElement';
export const wrapPageElement = CustomLayout;
export const wrapRootElement = CustomProviders;
A view components down in my navbar within Layout I am calling:
const { language, defaultLanguage } = useI18next();
console.log('locale', language);
When I am changing my page language with I18next, "locale" does not change value. "locale" does however change its value to the updated language if I am rendering the layout within my page.
I should note that I am using TypeScript for all of my project except the Gatsby lifecycle files, e.g. wrapPageElement.js
Any help is appreciated! Not sure where exactly the root cause could be at?
Additional code
Layout component
return (
<div className="page">
<Helmet>
<meta httpEquiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0,user-scalable=0" />
<meta name="description" content={props.description || description} />
<meta name="image" content={props.imagePath || image} />
<title>{props.title || title}</title>
{props.noIndex && <meta name="robots" content="noindex" />}
</Helmet>
<Navbar />
<main className="m-10 mt-60">{children}</main>
<Footer />
</div>
);
};
Navbar component
return (
<nav className="bg-green-300 w-full fixed top-0">
<ul className="flex flex-row gap-5 m-10">
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li className="ml-auto">
<ChangeLanguageLink language="en">EN</ChangeLanguageLink>
</li>
<li>
<ChangeLanguageLink language="th">TH</ChangeLanguageLink>
</li>
</ul>
</nav>
);
ChangeLanguageLink component
const ChangeLanguageLink: React.FC<React.PropsWithChildren<ChangeLanguageLinkProps>> = ({ children, ...props }) => {
const { originalPath } = useI18next();
return (
<LocalizedLink {...props} to={addFinalSlash(originalPath)}>
{children}
</LocalizedLink>
);
};
What I extract is that you are trying to use I18next
to update the state but you may not need to wrap your whole application to achieve that. The const { language, defaultLanguage } = useI18next();
will give you the current language.
That said, if you keep wanting your approach, wrapPageElement
and wrapRootElement
are wrappers (hence the name) that are shared between Gatsby SSR and Gatsby Browser so in the gatsby-ssr.js
you need to add the exact information:
import CustomProviders from './wrapWithProvider';
import CustomLayout from './wrapPageElement';
export const wrapPageElement = CustomLayout;
export const wrapRootElement = CustomProviders;
Keep in mind that wrapRootElement
is a wrapper that is never unmounted across the application.