ReactでGoogle Analyticsを動的に埋め込む方法(gtag.js使用)

# この記事でまとめる内容
Google AnalyticsのトラッキングID または 測定IDは、envファイル等で決まった値を定義しておくのが一般的かと思いますが、
バックエンドのAPIからトラッキングID または 測定IDを取得して動的な埋め込みが必要なケースがあったのでその実装方法についてまとめたいと思います。

# gtag.jsを使用する理由
まず超重要なトラッキングIDと測定IDの違いについて

- トラッキングID
    - ユニバーサル アナリティクス プロパティのID
    - `UA-`で始まる形式のID
- 測定ID
    - Google アナリティクス 4 プロパティのID
    - `G-`で始まる形式のID

参考
https://support.google.com/analytics/answer/9539598?hl=ja

事の始まりはこの辺りをちゃんと理解せずにとりあえず[react-ga](https://www.npmjs.com/package/react-ga)を使ったことでした...

「React Google Analytics」でググる
　　　　　　　⬇︎
とりあえず出てきたreact-gaを使うことを決める
　　　　　　　⬇︎
Google Analyticsでプロパティ作る ← プロパティの種類についてよくわかってないので、デフォルトでGoogle アナリティクス 4 プロパティになっていたけどこの時全く気にせずw
　　　　　　　⬇︎
サンプルを見ながらお試しで実装してみる
　　　　　　　⬇︎
あれ全くトラッキングできてない...？

と頭を抱えていましたが、理由はこちらの記事を読んでわかりました。

https://note.com/dd_techblog/n/n29535fd4f557

なるほど。react-gaが内包しているanalytics.jsでは、Google アナリティクス 4 プロパティに対応していなかったのね。。

なので、今回はこちらの記事を参考にgtag.jsを使用してAPIから取得したトラッキングID または 測定IDの埋め込み方法を整理していきます。

# さっそく本題
まずはこんな感じでGoogleAnalyticsに関する処理をまとめたファイルを作成します。

```ts:GoogleAnalyticsUtil.ts
import { useEffect } from 'react';
import { useHistory } from 'react-router-dom';

// idで検索できるように埋め込むscript用の名前を定義
const SCRIPT1_NAME = 'gtag';
const SCRIPT2_NAME = 'gtagScript';

/** gtag.js読み込み用関数 */
export const initializeGA = (googleAnalyticsId: string): void => {
  // scriptが既にある場合は一度削除
  document.getElementById(SCRIPT2_NAME)?.remove();
  document.getElementById(SCRIPT1_NAME)?.remove();

  // トラッキングID or 測定IDが空の場合は終了
  if (googleAnalyticsId === '') return;

  // gtag.jsをheadタグに埋め込み
  const script1 = document.createElement('script');
  script1.id = SCRIPT1_NAME;
  script1.src = `https://www.googletagmanager.com/gtag/js?id=${googleAnalyticsId}`;
  script1.async = true;
  document.head.appendChild(script1);

  // 実行用scriptをheadタグに埋め込み
  const script2 = document.createElement('script');
  script2.id = SCRIPT2_NAME;
  script2.text = `window.dataLayer = window.dataLayer || [];
  function gtag() { dataLayer.push(arguments); }
  gtag('js', new Date());
  gtag('config', '${googleAnalyticsId}');`;
  document.head.appendChild(script2);
};

declare global {
  /* eslint-disable @typescript-eslint/no-unused-vars */
  interface Window {
    gtag?: (
      key: string,
      trackingId: string,
      // eslint-disable-next-line camelcase
      config: { page_path: string }
    ) => void;
  }
}

/** トラッキング用関数 */
export const useTracking = (googleAnalyticsId: string): void => {
  const { listen } = useHistory();
  useEffect(() => {
    const unlisten = listen((location) => {
      if (!window.gtag) return;
      if (googleAnalyticsId === '') return;
      window.gtag('config', googleAnalyticsId, { page_path: location.pathname });
    });

    return unlisten;
  }, [googleAnalyticsId, listen]);
};
```

あとはこの関数を埋め込むだけです。
こんな感じでreact-router-domでページを切り替える画面があるとします。

```tsx:MainApp.tsx
import React from 'react';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import TopContainer from './containers/TopContainer';
import HogeContainer from './containers/HogeContainer';
import FugaContainer from './containers/FugaContainer';

const MainApp: React.FC = () => {
  return (
    <Router>
      <Switch>
        <Route exact path="/" component={TopContainer} />
        <Route path="/hoge" component={HogeContainer} />
        <Route path="/fuga" component={FugaContainer} />
      </Switch>
    </Router>
  );
};

export default MainApp;
```

こちらを以下のように修正します。

```tsx:MainApp.tsx
import React from 'react';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import TopContainer from './containers/TopContainer';
import HogeContainer from './containers/HogeContainer';
import FugaContainer from './containers/FugaContainer';
import { initializeGA, useTracking } from './utils/GoogleAnalyticsUtil'; // ⭐️これを追加

const MainApp: React.FC = ({ googleAnalyticsId: string }) => {
  // ⭐️これを追加
  useEffect(() => {
    // GoogleAnalytics gtag.js読み込み
    initializeGA(googleAnalyticsId);
  }, [googleAnalyticsId]);
  
  // ⭐️これを追加
  // GoogleAnalytics トラッキング
  useTracking(googleAnalyticsId);

  return (
    <Router>
      <Switch>
        <Route exact path="/" component={TopContainer} />
        <Route path="/hoge" component={HogeContainer} />
        <Route path="/fuga" component={FugaContainer} />
      </Switch>
    </Router>
  );
};

export default MainApp;
```

`googleAnalyticsId`がAPIから取得したトラッキングID または 測定IDです(この取得処理の部分については今回は省略しています)
`initializeGA`は、useEffectの第二引数に`googleAnalyticsId`を指定しているので、値に変更があった時のみgtag.jsを書き換えてくれます。
あとは`useTracking`内の処理によってページ移動(切り替え)が行われる度にトラッキングが行われます。
以上、Google Analyticsを動的に埋め込む方法でした。