Next.js v.13のApp Directry × Google Analytics・トラッキングでお困りのあなたへ（TypeScript）

おはこんハロチャオ～
ということで最近Next.js13でポケモン関連のwebアプリを作ったのですが、
Next.js13のApp Directryを触れるのが初めてだったので苦戦。。。

特にAnalyticsは避けて通れないのにもかかわらず日本語の情報が不足している感じがしたので、解決方法をお伝えできればと思います


ちなみに作ったのは、ポケモンのタイプ相性を詳細に知れるサービスです
バトル向けに使いやすい機能を追加していくつもりなので、よかったら見ていってください

https://www.pokebato.net/

## 前提
Google Analyticsを導入した回数もそんなに多くないので、前と同じように調べながら進めていました。

https://panda-program.com/posts/nextjs-google-analytics

とりあえず、このようなサイトを使ってあーこんなのあったなで進めていきました
一応、これはClient Componentを使うべきだと思ったので、`layout.tsx`から切り離して作ったりしました
周辺はこんな感じになっています
```typescript: app/head.tsx
import GoogleAnalytics from "../components/GoogleAnalytics";

const Head = () => {
  return (
    <>
      // title, metaなど省略
      <GoogleAnalytics />
    </>
  );
};

export default Head;
```
```typescript: lib/gtag.ts
export const GA_MEASUREMENT_ID = process.env.NEXT_PUBLIC_GA_ID || "";

export const existsGaId = GA_MEASUREMENT_ID !== "";

export const pageview = (path: string) => {
  window.gtag("config", GA_MEASUREMENT_ID, {
    page_path: path,
  });
};
```

GA_IDについては`.env.local`に入れておきます
`NEXT_PUBLIC_`を忘れずに
```.env.local
NEXT_PUBLIC_GA_ID=********
```

gtagについては型がないのでインストールします
```
yarn add -D @types/gtag.js
```
```typescript: types/gtag.d.ts
/// <reference types="gtag.js" />

    declare module 'gtag.js';
```

実際にGAのコードを呼び出したりする部分はclient componentとして切り分けましたが、そこで問題が発生しました

## 起きた問題：router.eventsできないんだけど
問題が起きたのはここです
```typescript: GoogleAnalytics.tsx
"use client";

import { useRouter } from "next/router";
import Script from "next/script";
import { useEffect } from "react";
import { existsGaId, GA_MEASUREMENT_ID, pageview } from "../lib/gtag";

const GoogleAnalytics = () => {
  const router = useRouter()

  useEffect(() => {
    if (!existsGaId) return
    const handleRouteChange = (path) => pageview(path)
    router.events.on('routeChangeComplete', handleRouteChange)

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

  return (
    <>
      <Script
        strategy="lazyOnload"
        src={`https://www.googletagmanager.com/gtag/js?id=${GA_MEASUREMENT_ID}`}
      />
      <Script id="gtag-init" strategy="afterInteractive">
        {`
          window.dataLayer = window.dataLayer || [];
          function gtag(){dataLayer.push(arguments);}
          gtag('js', new Date());
          gtag('config', '${GA_MEASUREMENT_ID}', {
            page_path: window.location.pathname,
          });
        `}
      </Script>
    </>
  );
};

export default GoogleAnalytics;
```

ここの`router.events`でエディタから「そんなのないよ」って言われちゃいました
どうやらNext.js 13から router.eventsがサポートされていないよう

https://beta.nextjs.org/docs/api-reference/use-router#:~:text=replaced%20by%20useSearchParams()-,router.events,-is%20not%20currently

## 解決法
同じケースないかなーって探しているとGoogle Analyticsではありませんがこんなのを見つけました

https://www.adamrichardson.dev/blog/track-analytics-events-in-next-app-directory

うーん、どうやら`next/navigation`に移行するらしい？
でも情報が少ない

と思ったら、参考にしたブログを作っている方がZennでいろいろ発信していました

https://zenn.dev/panda_program/scraps/6c66f160636969#:~:text=GoogleAnalytics.tsx%20%E3%82%92%20CC

灯台下暗しって感じですね、、、
こちらの[discussion](https://github.com/vercel/next.js/discussions/41745#discussioncomment-3987025)によると、どうやらこれからはこんな感じで置き換えてとのこと
```typescript
'use client'
import {usePathname, useSearchParams} from 'next/navigation'

function useNavigationEvent() {
  const pathname = usePathname()
  const searchParams = useSearchParams()
   useEffect(() => {
      const url = pathname + searchParams.toString()
      sendSomewhere(url)
   }, [pathname, searchParams])
}
```

## 完成型
ということでそれに合わせて変更を入れて完成です

```typescript: GoogleAnalytics.tsx
"use client";

import { usePathname, useSearchParams } from "next/navigation";
import Script from "next/script";
import { useEffect } from "react";
import { existsGaId, GA_MEASUREMENT_ID, pageview } from "../lib/gtag";

const GoogleAnalytics = () => {
  const pathname = usePathname();
  const searchParams = useSearchParams();

  useEffect(() => {
    if (!existsGaId) {
      return
    }
    const url = pathname + searchParams.toString()
    pageview(url)
  }, [pathname, searchParams])

  return (
    <>
      <Script
        strategy="lazyOnload"
        src={`https://www.googletagmanager.com/gtag/js?id=${GA_MEASUREMENT_ID}`}
      />
      <Script id="gtag-init" strategy="afterInteractive">
        {`
          window.dataLayer = window.dataLayer || [];
          function gtag(){dataLayer.push(arguments);}
          gtag('js', new Date());
          gtag('config', '${GA_MEASUREMENT_ID}', {
            page_path: window.location.pathname,
          });
        `}
      </Script>
    </>
  );
};

export default GoogleAnalytics;
```

参考になるとうれしいです

作ったサービスもよかったら見ていってください

https://www.pokebato.net/