From 1494e2f6fc3e34dbd83ef61163f4d796ec9d7d60 Mon Sep 17 00:00:00 2001 From: DongjaJ Date: Mon, 27 May 2024 18:27:44 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EA=B5=AC=EA=B8=80=20=EC=95=A0=EB=84=90?= =?UTF-8?q?=EB=A6=AC=ED=8B=B1=EC=8A=A4=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 6 ++++++ package.json | 1 + src/App.tsx | 3 +++ src/components/RouterTracker.tsx | 30 ++++++++++++++++++++++++++++++ 4 files changed, 40 insertions(+) create mode 100644 src/components/RouterTracker.tsx diff --git a/package-lock.json b/package-lock.json index 3ed39c4f..eda3503c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-error-boundary": "^4.0.11", + "react-ga4": "^2.1.0", "react-hook-form": "^7.46.0", "react-icons": "^4.11.0", "react-router-dom": "^6.15.0" @@ -15223,6 +15224,11 @@ "react": ">=16.13.1" } }, + "node_modules/react-ga4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/react-ga4/-/react-ga4-2.1.0.tgz", + "integrity": "sha512-ZKS7PGNFqqMd3PJ6+C2Jtz/o1iU9ggiy8Y8nUeksgVuvNISbmrQtJiZNvC/TjDsqD0QlU5Wkgs7i+w9+OjHhhQ==" + }, "node_modules/react-hook-form": { "version": "7.46.0", "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.46.0.tgz", diff --git a/package.json b/package.json index ab98b6d2..57d3b432 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-error-boundary": "^4.0.11", + "react-ga4": "^2.1.0", "react-hook-form": "^7.46.0", "react-icons": "^4.11.0", "react-router-dom": "^6.15.0" diff --git a/src/App.tsx b/src/App.tsx index 4ee0a3d8..73b13386 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,6 +1,7 @@ import { Suspense, useEffect } from 'react'; import { Outlet } from 'react-router-dom'; import { getItemFromStorage, setItemToStorage } from '@/utils/localStorage'; +import RouteChangeTracker from '@components/RouterTracker'; import { useThemeContext } from '@hooks/useThemeContext'; import { ToastContextProvider } from './context/ToastContext'; import { LoadingPage } from './pages'; @@ -9,6 +10,8 @@ import MockUpPage from './pages/MockUpPage'; const App = () => { const { theme, updateDarkMode } = useThemeContext(); + RouteChangeTracker(); + useEffect( () => { if ( diff --git a/src/components/RouterTracker.tsx b/src/components/RouterTracker.tsx new file mode 100644 index 00000000..c84fda35 --- /dev/null +++ b/src/components/RouterTracker.tsx @@ -0,0 +1,30 @@ +import { useEffect, useState } from 'react'; +import ReactGA from 'react-ga4'; +import { useLocation } from 'react-router-dom'; + +/** + * uri 변경 추적 컴포넌트 + * uri가 변경될 때마다 pageview 이벤트 전송 + */ +const RouteChangeTracker = () => { + const location = useLocation(); + const [initialized, setInitialized] = useState(false); + + // 구글 애널리틱스 운영서버만 적용 + useEffect(() => { + if (import.meta.env.REACT_APP_GOOGLE_ANALYTICS) { + ReactGA.initialize(import.meta.env.REACT_APP_GOOGLE_ANALYTICS); + setInitialized(true); + } + }, []); + + // location 변경 감지시 pageview 이벤트 전송 + useEffect(() => { + if (initialized) { + ReactGA.set({ page: location.pathname }); + ReactGA.send('pageview'); + } + }, [initialized, location]); +}; + +export default RouteChangeTracker;