remix hydration error when using gtag
pullmann4rent opened this issue · comments
pullmann4rent commented
Reproduction
Root
import * as gtag from "~/utils/gtag";
export default function App() {
const { showBanner, gaTrackingId } = useLoaderData<typeof loader>();
const location = useLocation();
useEffect(() => {
if (gaTrackingId?.length) {
gtag.pageview(location.pathname, gaTrackingId);
}
}, [location, gaTrackingId]);
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<script async src={`https://www.googletagmanager.com/gtag/js?id=${gaTrackingId}`}></script>
<script async dangerouslySetInnerHTML={{ __html: `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '${gaTrackingId}');
`
}} />
<Suspense fallback={null}>
<script async dangerouslySetInnerHTML={{ __html: `
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','xxxx');
`
}} />
</Suspense>
<Meta />
<Links />
<ExternalScripts />
</head>
<body>
<>
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=XXXX"
height="0" width="0" style={{display: 'none',visibility:'hidden'}}></iframe></noscript>
<Whatsapp />
<Outlet />
<ScrollRestoration />
<Scripts />
<LiveReload />
</body>
</html>
);
}
export async function loader({ request }: LoaderArgs) {
const cookieHeader = request.headers.get("Cookie");
const cookie = await userPrefs.parse(cookieHeader);
return json({ showBanner: cookie ?? null, gaTrackingId: 'xxx' });
}
gtag util
declare global {
interface Window {
gtag: (
option: string,
gaTrackingId: string,
options: Record<string, unknown>,
) => void;
}
}
/**
* @example
* https://developers.google.com/analytics/devguides/collection/gtagjs/pages
*/
export const pageview = (url: string, trackingId: string) => {
if (!window.gtag) {
console.warn(
"window.gtag is not defined. This could mean your google analytics script has not loaded on the page yet.",
);
return;
}
window.gtag("config", trackingId, {
page_path: url,
});
};
/**
* @example
* https://developers.google.com/analytics/devguides/collection/gtagjs/events
*/
export const event = ({
action,
category,
label,
value,
}: Record<string, string>) => {
if (!window.gtag) {
console.warn(
"window.gtag is not defined. This could mean your google analytics script has not loaded on the page yet.",
);
return;
}
window.gtag("event", action, {
event_category: category,
event_label: label,
value: value,
});
};
System Info
System:
OS: Windows 10 10.0.19045
CPU: (4) x64 AMD FX(tm)-4170 Quad-Core Processor
Memory: 1.75 GB / 7.98 GB
Binaries:
Node: 18.18.0 - C:\Program Files\nodejs\node.EXE
Yarn: 1.22.21 - ~\AppData\Roaming\npm\yarn.CMD
npm: 10.2.0 - C:\Program Files\nodejs\npm.CMD
Browsers:
Edge: Chromium (123.0.2420.97)
Internet Explorer: 11.0.19041.3636
npmPackages:
@remix-run/css-bundle: ^2.0.1 => 2.7.1
@remix-run/dev: ^1.15.0 => 1.19.3
@remix-run/eslint-config: ^1.15.0 => 1.19.3
@remix-run/express: ^1.15.0 => 1.19.3
@remix-run/node: ^1.15.0 => 1.19.3
@remix-run/react: ^1.15.0 => 1.19.3
@remix-run/serve: ^1.15.0 => 1.19.3
@remix-run/vercel: ^1.15.0 => 1.19.3
Used Package Manager
npm
Expected Behavior
That I got no hydration err
Actual Behavior
Google analatiycs works but not google tag manager. I got hydration error when I use this code:
<Suspense fallback={null}>
<script async dangerouslySetInnerHTML={{ __html: `
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','xxxx');
`
}} />
</Suspense>
su commented
To fix this, we recommend the using the ClientOnly component in the remix-utils community package. An example of its usage can be found in the examples repository.