如何在 nextJS 打字稿中添加 GTM(window.dataLayer 不是函数)

时间:2021-01-05 17:16:37

标签: typescript next.js google-tag-manager google-datalayer

我正在我的网站上实施 GTM,但我的 NextJS 项目是在 Typescript 中。 我用的是 Github the example of Github 的例子,但是出现这个错误: 类型错误:window.dataLayer 不是函数 image

这是我的 gtm.js 文件:

export const GTM_ID = process.env.TAG_MANAGER

export const pageview = (url) => {
  window.dataLayer({
    event: 'pageview',
    page: url,
  })
}

是的,GTM 在 js 中,但我所有的项目都在 ts/tsx 中

我的 _app.tsx 和我的 _document.tsx 和 vercel 的例子一样,我用 ID 创建了组件和 .env。

一切都与应该工作的示例相同。

编辑

我改变了一些东西

我的 _document.tsx:

import Document, { DocumentContext, DocumentInitialProps, Head, Html, Main, NextScript } from 'next/document'
import { ServerStyleSheet } from 'styled-components'
import favicon from '../assets/favicon.ico'
import { GA_TRACKING_ID } from '../lib/gtag'
import { GTM_ID } from '../lib/gtm'

export default class MyDocument extends Document {
  static async getInitialProps(ctx: DocumentContext): Promise<DocumentInitialProps> { //oda func async recebe promise
    const sheet = new ServerStyleSheet()
    const originalRenderPage = ctx.renderPage

    try {
      ctx.renderPage = () =>
        originalRenderPage({
          enhanceApp: (App) => (props) =>
            sheet.collectStyles(<App {...props} />),
        })

      const initialProps = await Document.getInitialProps(ctx)
      return {
        ...initialProps,
        styles: (
          <>
            {initialProps.styles}
            {sheet.getStyleElement()}
          </>
        ),
      }
    } finally {
      sheet.seal()
    }
  }

  render(): JSX.Element {
    //change HTML lang
    return(
      <Html lang={"pt"}>
        <Head>
          <meta charSet="utf-8" />
          <link rel="preconnect" href="https://fonts.gstatic.com"></link>
          <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap" rel="stylesheet"></link>
          <link rel="icon" href={favicon} />
          <meta name="theme-color" content="#448757" />
          <link rel="apple-touch-icon" href={favicon}></link>

          {/* Global Site Tag (gtag.js) - Google Analytics */}
          <script
            async
            src={`https://www.googletagmanager.com/gtag/js?id=${GA_TRACKING_ID}`}
          />
          <script
            dangerouslySetInnerHTML={{
              __html: `
            window.dataLayer = window.dataLayer || [];
            function gtag(){dataLayer.push(arguments);}
            gtag('js', new Date());
            gtag('config', '${GA_TRACKING_ID}', {
              page_path: window.location.pathname,
            });
          `,
            }}
          />

          {/* Google Tag Manager - Global base code */}
          <script
            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', '${GTM_ID}');
              `,
            }}
          />

        </Head>
        <body>
          <noscript>
            <iframe
              src={`https://www.googletagmanager.com/ns.html?id=${GTM_ID}`}
              height="0"
              width="0"
              style={{ display: 'none', visibility: 'hidden' }}
            />
          </noscript>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

我的 _app.tsx:

import { AppProps } from 'next/app'
import GlobalStyles  from '../styles/GlobalStyles'
import dynamic from 'next/dynamic'
import { traducao } from '../translate/index'
import { useRouter, Router } from "next/router"
import * as gtag from '../lib/gtag'
import { GTMPageView } from '../lib/gtm'
import React, { useEffect } from 'react';

const MyApp: React.FC<AppProps> = ({ Component, pageProps }) => {
  //Gtag
  const router = useRouter()
    useEffect(() => {
      const handleRouteChange = (url) => {
        gtag.pageview(url)
      }

      router.events.on('routeChangeComplete', handleRouteChange)
        return () => {
          router.events.off('routeChangeComplete', handleRouteChange)
      }
    }, [router.events])


    // Initiate GTM
    useEffect(() => {
      const handleRouteChange = (url: string) => GTMPageView(url);
      Router.events.on('routeChangeComplete', handleRouteChange);
      return () => {
          Router.events.off('routeChangeComplete', handleRouteChange);
      };
    }, []);
  return (
    <>
      <Component {...pageProps}/>
      <GlobalStyles />
    </>
  )
}

export default MyApp

我的新 gtm.ts:

export const GTM_ID = process.env.NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID


export const GTMPageView = (url: string) => {
  interface PageEventProps {
      event: string;
      page: string;
  }

  const pageEvent: PageEventProps = {
      event: 'pageview',
      page: url,
  };
  //@ts-ignore
  window && window.dataLayer && window.dataLayer.push(pageEvent);
  return pageEvent;
};

运作良好

但我不知道它在 GTM 中是否有效,因为我的网站仍在开发中(本地主机)...

window.datalayer 脚本错误消失了,但知道这是我的灯塔:

image

Google 灯塔错误的最佳做法

1 个答案:

答案 0 :(得分:0)

您可以使用 React Google Tag Manager 包简化您的生活。

https://github.com/alinemorelli/react-gtm

用法很简单:

在你的 _app.js 的函数组件定义中

React.useEffect(() => {

    if (typeof window !== 'undefined') {
      console.log("init GTM")
      TagManager.initialize({ gtmId: 'YOUR_GTM_ID' });
    }else {
      console.log("GTM server side - ignorning")
    }

}, [])