如何为React-Router设置Google Analytics?

120

我正在尝试在我的react网站上设置Google Analytics,并找到了几个包,但没有一个与我在示例方面的设置相匹配。希望有人可以解决这个问题。

我看的包是react-ga

我的index.js上的渲染方法如下。

React.render((
<Router history={createBrowserHistory()}>
    <Route path="/" component={App}>
        <IndexRoute component={Home} onLeave={closeHeader}/>
        <Route path="/about" component={About} onLeave={closeHeader}/>
        <Route path="/gallery" component={Gallery} onLeave={closeHeader}/>
        <Route path="/contact-us" component={Contact} onLeave={closeHeader}>
            <Route path="/contact-us/:service" component={Contact} onLeave={closeHeader}/>
        </Route>
        <Route path="/privacy-policy" component={PrivacyPolicy} onLeave={closeHeader} />
        <Route path="/feedback" component={Feedback} onLeave={closeHeader} />
    </Route>
    <Route path="*" component={NoMatch} onLeave={closeHeader}/>
</Router>), document.getElementById('root'));

4
下面发布了有关react-router-4/react-router-dom的答案,这里的顶级答案适用于早期版本的react-router,不幸的是无法与v4一起使用。 - Peter Berg
我该如何在使用React SSR时与StaticRouter一起添加它? - Subhendu Kundu
15个回答

102

保持对您的历史对象的引用,例如:

import { createBrowserHistory } from 'history';

var history = createBrowserHistory();

ReactDOM.render((
    <Router history={history}>
        [...]

然后添加一个监听器来记录每个页面的浏览量。(这假设您已经按照通常的方式设置了window.ga对象。)

history.listen((location) => {
    window.ga('set', 'page', location.pathname + location.search);
    window.ga('send', 'pageview');
});

16
这不会考虑到发送的事件或其他点击类型。它们仍然会在页面加载时参考URL。相反,在发送页面视图之前,您需要在跟踪器上设置新值,例如 ga('set', 'page', location.pathname + location.search); ga('send', 'pageview'); - Philip Walton
2
嗨,David,你的示例是使用来自ga网站的常规ga代码还是使用react-ga包?谢谢。 - John Fu
你不想在发送命令中加入第三个参数。虽然技术上,对于页面视图 hit 的 send 命令可以接受一个可选的页面字段作为第三个参数,但是当跟踪单页面应用程序时,不建议通过这种方式传递页面字段。这是因为通过 send 命令传递的字段不会设置在跟踪器上——它们仅适用于当前 hit。如果不更新跟踪器,那么如果您的应用程序发送任何非页面视图 hit(例如事件或社交交互),那么这些 hit 将与跟踪器创建时具有的页面值关联。 - Joshua Robinson
https://developers.google.com/analytics/devguides/collection/analyticsjs/single-page-applications - Joshua Robinson
始终遵循库的推荐方式:https://dev59.com/E1sW5IYBdhLWcg3wi36j#52464888 - Paras
显示剩余2条评论

65
这个问题是关于react-ga的,但是这个包很快就会过时,因为它不支持Google Analytics 4。下面是一个通用的解决方案,适用于任何库或本地gtag。要将GA4添加到React,请查看此答案:https://dev59.com/XlIG5IYBdhLWcg3whwmc#73354959
自从react-router v5.1.0以来,可以更轻松地使用useLocation来解决这个问题。

usePageTracking.js

import { useEffect } from "react";
import { useLocation } from "react-router-dom";

const usePageTracking = () => {
  const location = useLocation();

  useEffect(() => {
    // track pageview with gtag / react-ga / react-ga4, for example:
    window.gtag("event", "page_view", {
      page_path: location.pathname + location.search,
    });
  }, [location]);
};

export default usePageTracking;

App.js

const App = () => {
  usePageTracking();

  return (...);
};

请记住,Google Analytics会自动跟踪页面,但这并不适用于每种情况。例如,不会跟踪哈希和搜索参数的更改。这可能会导致很多混淆。例如,当使用HashRouter或锚链接时,将无法跟踪导航。要完全控制页面视图跟踪,您可以禁用自动跟踪。详细说明请参见:The Ultimate Guide to Google Analytics (UA & GA4) on React (Or Anything Else)
您可以在cra-typescript-starter中查看此项工作方式,我正在使用它与GA4一起使用。

3
最新的“gtag”可能不必要。当我浏览时,GA调试器似乎能够正确记录推送事件:“正在处理数据层推送:{event:” gtm.historyChange-v2 “,gtm.historyChangeSource:”pushState“,gtm.oldUrlFragment:“”,gtm.newUrlFragment:“”,gtm.oldHistoryState:null,gtm.newHistoryState:{key:”j5xoc4“,state:undefined},gtm.oldUrl:”https://site/“,gtm.newUrl:”https://site/new-url?search-params“,gtm.triggers:”1_36“}”,并且GA仪表板中显示了一个新的页面视图。 - Dattaya
4
我找到了最好和优雅的解决方案,谢谢。只是需要注意,在App.js中调用useLocation,您必须在index.js中添加<Router>,像这样:<Router><App /></Router>,并在顶部导入Router,使用import { BrowserRouter as Router } from 'react-router-dom'; - Francesco Orsi
@FrancescoOrsi,这绝对正确,而且使用TypeScript时,它会警告您缺少Route组件。 - Marcello DeSales
@thisismydesign 你有没有想过为什么 page_view 被跟踪了两次?我的 useEffect 每次路由改变只会触发一次,但是 page_view 却被跟踪了两次。 - fabpico
@fabpico 如果您手动跟踪页面浏览,请禁用自动页面跟踪:https://developers.google.com/analytics/devguides/collection/gtagjs/pages#disable_pageview_measurement 我会更新答案以反映这一点。 - thisismydesign
@thisismydesign,我已经尝试过了,但仍然每次路由更改都会跟踪两次页面浏览。我在 https://stackoverflow.com/questions/73390801/react-router-5-google-analytics-4-page-view-tracks-twice?noredirect=1#comment129607889_73390801 中打开了一个线程。 - fabpico

34

假设Google Analytics已加载并初始化了跟踪ID。

以下是针对React-Router版本4的解决方案,使用<Route>组件来跟踪页面浏览量。

<Route path="/" render={({location}) => {
  if (typeof window.ga === 'function') {
    window.ga('set', 'page', location.pathname + location.search);
    window.ga('send', 'pageview');
  }
  return null;
}} />

你只需在<Router>中呈现此组件(但不作为<Switch>的直接子项)。

发生的情况是,每当位置属性更改时,它会导致此组件重新渲染(实际上不会渲染任何内容),从而触发页面查看事件。


1
React-router 4. 它有什么做不到的?! - Anthony Cregan
1
下面发布了另一个react-router-4的解决方案,它不涉及修改单个路由。可悲的是,这绝对是一种“选择你的毒药”类型的情况。 - Peter Berg
1
这难道不意味着访问“/”将不会显示任何内容吗? - Dana Woodman
3
@DanaWoodman,只需另外创建一条路由并发出您想要的内容即可。这假设该路由不在“Switch”中。 - bozdoz
2
这个人应该获得诺贝尔奖,我们已经尝试了各种方法,但只有他的方法没有任何缺陷。谢谢! - Danilo Cunha
显示剩余2条评论

32
我将使用React Router v4和谷歌分析全站标签,这似乎是在撰写本文时推荐的。
以下是我的解决方案:
创建一个组件,使用react-router-dom中的withRouter进行包装:
import React from 'react';
import { withRouter } from 'react-router-dom';
import { GA_TRACKING_ID } from '../config';

class GoogleAnalytics extends React.Component {
    componentWillUpdate ({ location, history }) {
        const gtag = window.gtag;

        if (location.pathname === this.props.location.pathname) {
            // don't log identical link clicks (nav links likely)
            return;
        }

        if (history.action === 'PUSH' &&
            typeof(gtag) === 'function') {
            gtag('config', GA_TRACKING_ID, {
                'page_title': document.title,
                'page_location': window.location.href,
                'page_path': location.pathname
            });
        }
    }

    render () {
        return null;
    }
}

export default withRouter(GoogleAnalytics);

只需在你的路由器中添加该组件(我认为最好是在匹配任何路由和任何Switch组件之后,因为分析函数不应优先于站点渲染):

import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import IndexPage from './IndexPage';
import NotFoundPage from './NotFoundPage';
import GoogleAnalytics from './GoogleAnalytics';

const App = () => (
    <Router>
        <Switch>
            <Route exact path="/" component={IndexPage} />
            <Route component={NotFoundPage} />
        </Switch>
        <GoogleAnalytics />
    </Router>
);

如下所述:

使用withRouter的组件会在每次路由更改时重新渲染,其props与render props相同

因此,当路由更改时,GoogleAnalytics组件将更新,它将接收新的位置作为props,而history.action将是PUSH表示新的历史记录项,或者是POP表示通过历史记录向后导航(我认为不应该触发页面视图,但您可以根据需要调整componentWillUpdate中的if语句(甚至可以尝试使用componentDidUpdatethis.props,但我不确定哪个更好)。


1
@me-me 是的。但是在 body 标签内:<body> ... <script ...></script></body>。 - bozdoz
这不是准确的。页面浏览量不仅仅是推送历史操作。如果使用这种方式,那么页面浏览量的定义就被定制了。当与行业基准进行比较时,你正在比较苹果和橙子。因为你的页面浏览量定义是非标准的。标准定义包括像从后退按钮中弹出等操作。请参见 Google 的标准定义:https://support.google.com/analytics/answer/1257084?hl=en - Joshua Robinson
2
嘿@JoshuaRobinson,我在底部写道,“...我认为不应该触发页面视图,但你可以调整...”。这个问题是关于将Google Analytics与React Router集成,而不是关于应该记录哪些视图。话虽如此,我可能会调整我的组件,因为Google在他们的端上会以不同的方式跟踪它。谢谢。 - bozdoz
你有没有解决方案可以在页面加载时触发?因为这只有在历史记录改变时才有效。 - Kaherdin
删除 history.action === 'push',或者更好的方法是在其中添加一个带有相同 gtag 脚本的 componentDidMount。 - bozdoz
显示剩余4条评论

20

如果您正在使用来自react-router-4react-router-dom包,您可以这样处理:

import { Router, Route } from 'react-router-dom';
import { createBrowserHistory } from 'history';

const history = createBrowserHistory();
const initGA = (history) => {
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

  ga('create', 'YOUR_IDENTIFIER_HERE', 'auto');
  ga('send', 'pageview');

  history.listen((location) => {
    console.log("tracking page view: " + location.pathname);
    ga('send', 'pageview', location.pathname);
  });
};

initGA(history);

class App extends Component { //eslint-disable-line
  render() {
    return
      (<Router history={history} >
         <Route exact path="/x" component={x} />
         <Route exact path="/y" component={y} />
       </Router>)
  }
}
请注意,这需要您安装history包(npm install history)。这已经是react-router-dom的依赖项,因此您不会增加任何页面权重。
还要注意:无法同时使用BrowserRouter组件和此种方式来跟踪ga。这没关系,因为BrowserRouter 组件只是 Router 对象的一个非常简单的包装器。我们在这里使用 <Router history={history}> 重新创建了 BrowserRouter 的功能,其中const history = createBrowserHistory();

1
你从未调用过initGA函数吗? - Muhammad Umer
@MuhammadUmer 是的,已经修复了。 - Peter Berg
为什么不在静态HTML中添加GA呢?我点了个赞。因为我认为监听history对象是正确的方法。 - Vince V.
@VinceV。你可以在构建过程中初始化history对象,然后将历史记录存储在window对象上,并在<head>标签中的脚本标记中访问它,但我认为这最终会使你的构建流程更加复杂。 ¯_(ツ)_/¯ - Peter Berg
如果您正在使用 BrowserRouter 组件,请查看下面提供的替代解决方案的答案。 - Toshe
这是最简单的答案,在这里起作用了。谢谢! - vmf91

18

我建议使用优秀的react-router-ga包,这个包非常轻量级且易于配置,特别是在使用BrowserRouter包装器时。

导入组件:

import Analytics from 'react-router-ga';

然后只需在您的BrowserRouter中添加<Analytics>即可:

<BrowserRouter>
    <Analytics id="UA-ANALYTICS-1">
        <Switch>
            <Route path="/somewhere" component={SomeComponent}/>
        </Switch>
    </Analytics>
</BrowserRouter>

3
如果用户只想追踪页面浏览量,这似乎是一个超级简单的解决方案。非常精简! - peyo
1
这适用于GA4吗? - coder

12

我喜欢Mark Thomas Müller在这里提出的建议:这里

在你的index.js

import ReactGA from 'react-ga'

ReactGA.initialize('YourAnalyticsID')

ReactDOM.render(<App />, document.getElementById('root'))

您的路由表存放在哪里:

import React, { Component } from 'react'
import { Router, Route } from 'react-router-dom'
import createHistory from 'history/createBrowserHistory'
import ReactGA from 'react-ga'

const history = createHistory()
history.listen(location => {
    ReactGA.set({ page: location.pathname })
    ReactGA.pageview(location.pathname)
})

export default class AppRoutes extends Component {
    componentDidMount() {
        ReactGA.pageview(window.location.pathname)
    }

    render() {
        return (
            <Router history={history}>
                <div>
                    <Route path="/your" component={Your} />
                    <Route path="/pages" component={Pages} />
                    <Route path="/here" component={Here} />
                </div>
            </Router>
        )
    }
}

简短、可伸缩和简单 :)


为什么需要跟踪,一个全局的,一个本地的? - Thellimist

6

始终使用库的推荐方法

在React-GA文档中,他们添加了一个社区组件,推荐与React Router一起使用:https://github.com/react-ga/react-ga/wiki/React-Router-v4-withTracker

实现

import withTracker from './withTracker';

ReactDOM.render(
  <Provider store={store}>
    <ConnectedRouter history={history}>
      <Route component={withTracker(App, { /* additional attributes */ } )} />
    </ConnectedRouter>
  </Provider>,
  document.getElementById('root'),
);

代码

import React, { Component, } from "react";
import GoogleAnalytics from "react-ga";

GoogleAnalytics.initialize("UA-0000000-0");

const withTracker = (WrappedComponent, options = {}) => {
  const trackPage = page => {
    GoogleAnalytics.set({
      page,
      ...options,
    });
    GoogleAnalytics.pageview(page);
  };

  // eslint-disable-next-line
  const HOC = class extends Component {
    componentDidMount() {
      // eslint-disable-next-line
      const page = this.props.location.pathname + this.props.location.search;
      trackPage(page);
    }

    componentDidUpdate(prevProps) {
      const currentPage =
        prevProps.location.pathname + prevProps.location.search;
      const nextPage =
        this.props.location.pathname + this.props.location.search;

      if (currentPage !== nextPage) {
        trackPage(nextPage);
      }
    }

    render() {
      return <WrappedComponent {...this.props} />;
    }
  };

  return HOC;
};

export default withTracker;

1
如果我使用服务器端渲染(SSR),则GA在不刷新页面的情况下无法知道实际页面标题。 - Francis Rodrigues
1
你可以使用React在挂载时更改标题。 - Paras
感谢您的发布! - Sailesh Kotha
store 是从哪里来的? - user_78361084
ProviderConnectedRouter 来自哪里?这是一个不完整的答案,应该被点踩。 - user_78361084
阅读帖子,包括文档链接@user_78361084。两者都是库的一部分。如果您仔细阅读答案,您就会明白。 - Paras

3

以下是一种最简单的跟踪所有路径的方法,需要做一些额外的工作:

npm i --save history react-ga

创建一个名为history.js的文件。

import { createBrowserHistory } from "history"
import ReactGA from "react-ga"

ReactGA.initialize(process.env.REACT_APP_GA)

const history = createBrowserHistory()
history.listen((location) => {
    ReactGA.pageview(location.pathname)
})

// workaround for initial visit
if (window.performance && (performance.navigation.type === performance.navigation.TYPE_NAVIGATE)) {
    ReactGA.pageview("/")
}

export default history

然后将其导入到设置了您的路由器的位置

import history from "./history"

...

class Route extends Component {
render() {
    return (
        <Router history={history}>
            <Switch>
              <Route path="/" exact component={HomePage} />
              ...
            </Switch>
        </Router>
    )
}

export default Route

参考资料:

Gustavo Gonzalez | medium.com

History | GitHub


2
首先,在您的index.js中设置onUpdate函数以调用ga。
import ga from 'ga.js';
onUpdate() {
  console.log('=====GA=====>', location.pathname);
  console.log('=====GA_TRACKING_CODE=====>', GA_TRACKING_CODE);
  ga("send", "pageview", location.pathname);
}

render() {
  return (
    <Router onUpdate={this.onUpdate.bind(this)}>...</Router>
  );
}

关于 ga.js:

'use strict';
if(typeof window !== 'undefined' && typeof GA_TRACKING_CODE !== 'undefined') {
  (function(window, document, script, url, r, tag, firstScriptTag) {
    window['GoogleAnalyticsObject']=r;
    window[r] = window[r] || function() {
      (window[r].q = window[r].q || []).push(arguments)
    };
    window[r].l = 1*new Date();
    tag = document.createElement(script),
    firstScriptTag = document.getElementsByTagName(script)[0];
    tag.async = 1;
    tag.src = url;
    firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
  })(
    window,
    document,
    'script',
    '//www.google-analytics.com/analytics.js',
    'ga'
  );

  var ga = window.ga;

  ga('create', GA_TRACKING_CODE, 'auto');

  module.exports = function() {
    return window.ga.apply(window.ga, arguments);
  };
} else {
  module.exports = function() {console.log(arguments)};
}

这里使用的路由器版本是哪个? - Pavan
这是针对React Router DOM v2或v3的,不适用于v4。 - Hugo Gresse

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接