【问题标题】:How to set up Google Analytics for React-Router?如何为 React-Router 设置 Google Analytics?
【发布时间】:2016-04-22 13:09:18
【问题描述】:

我正在尝试在我的 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'));

【问题讨论】:

  • 在下面发布了react-router-4/react-router-dom 的答案,这里的最佳答案是针对早期版本的 react-router,不幸的是,它不适用于 v4。
  • 当我使用 React SSR 时,如何使用 StaticRouter 添加它?

标签: google-analytics reactjs react-router


【解决方案1】:

保留对历史对象的引用。即

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');
});

【讨论】:

  • 这不会考虑发送的事件或其他命中类型。他们仍然会在页面加载时引用 URL。相反,您需要在发送综合浏览量之前在跟踪器上设置新值,例如ga('set', 'page', location.pathname + location.search); ga('send', 'pageview');.
  • 嗨,David,您的示例是使用来自 ga 站点的常规 ga 代码还是使用 react-ga 包?谢谢。
  • 尚未决定如何修复它,但这条信息也可能有用:stackoverflow.com/questions/30052693/…(它解释了为什么归因在某些情况下可能无法正常工作,并且还会引入高反弹率-费率)。
  • 您不希望发送命令中的第三个参数。 “虽然从技术上讲,页面浏览命中的发送命令接受可选页面字段作为第三个参数,但在跟踪单页应用程序时不建议以这种方式传递页面字段。这是因为通过发送命令传递的字段未在跟踪器上设置 -它们仅适用于当前点击。如果您的应用程序发送任何非综合浏览点击(例如事件或社交互动),则不更新跟踪器将导致问题,因为这些点击将与跟踪器在创建时所具有的任何页面值相关联。 "
【解决方案2】:

由于react-router v5.1.0,使用useLocation 可以更轻松地解决这个问题。

usePageTracking.js

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

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

  useEffect(() => {
    ReactGA.initialize("UA-000000000-0");
    ReactGA.pageview(location.pathname + location.search);
  }, [location]);
};

export default usePageTracking;

App.js

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

  return (...);
};

另见:

这是一个更智能的版本:

usePageTracking.js

import { useEffect, useState } from "react";
import { useLocation } from "react-router-dom";
import ReactGA from "react-ga";

const usePageTracking = () => {
  const location = useLocation();
  const [initialized, setInitialized] = useState(false);

  useEffect(() => {
    if (!window.location.href.includes("localhost")) {
      ReactGA.initialize("UA-000000000-0");
    }
    setInitialized(true);
  }, []);

  useEffect(() => {
    if (initialized) {
      ReactGA.pageview(location.pathname + location.search);
    }
  }, [initialized, location]);
};

export default usePageTracking;

【讨论】:

  • 我不确定最新的“gtag”是否有必要。当我导航时,ga 调试器似乎正确记录了推送事件:Processing data layer push: {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 仪表板中显示了一个新的页面视图
  • 我找到的最好最优雅的解决方案,谢谢。只是考虑一下,要在 App.js 中调用 useLocation,您必须像这样在 index.js 中添加 在顶部导入路由器,并使用 import { BrowserRouter as Router } from ' react-router-dom';
【解决方案3】:

鉴于谷歌分析已加载并使用跟踪 ID 进行初始化。

这里是 react-router 版本 4 的解决方案,使用 &lt;Route&gt; 组件跟踪页面浏览量。

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

您只需在 &lt;Router&gt; 内渲染此组件(但不能作为 &lt;Switch&gt; 的直接子代)。

发生的情况是,每当 location 属性发生变化时,它都会重新渲染该组件(实际上并不渲染任何内容),从而触发网页浏览。

【讨论】:

  • React-router 4. 有什么不能做的吗?!
  • 在下面发布了另一个不涉及修改单个路由的 react-router-4 解决方案。可悲的是,这绝对是一种“选择你的毒药”类型的情况。
  • 这不是说去“/”不会渲染吗?
  • 只有另一条路线可以发出你想要的任何东西@DanaWoodman。这假设路线不在Switch
  • 这个人应该获得诺贝尔奖,我们已经尝试了各种方式,但这是唯一一个没有缺点的人。谢谢!
【解决方案4】:

我正在使用 React Router v4 和 Google Analytics Global Site Tag,在撰写本文时似乎是推荐的。

这是我的解决方案:

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 将在每次路由更改时重新渲染其组件 与渲染道具相同的道具

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

【讨论】:

  • bozdoz 您是如何将全局站点标签添加到您的页面的。您是否刚刚将
  • @me-me 是的。但在正文标签内:&lt;body&gt; ... &lt;script ...&gt;&lt;/script&gt;&lt;/body&gt;
  • 最新的 React 和 React Router 需要进行一些调整。将componentWillMount 更改为componentDidMount。将page_path 更改为this.props.location.pathname。将 Switch 和 GoogleAnalytics 组件包装在
  • 不确定您在哪里看到 componentWillMount,也不确定 page_path 有何不同,但我会尝试将 Switch 和 GA 组件包装在 &lt;React.Fragment&gt; 中,而不是 div。谢谢!
  • 嘿@JoshuaRobinson,我在底部写道,“......我认为不应该触发页面视图,但你可以调整......”。这个问题是关于将 Google Analytics 与 React Router 集成,而不是关于应该记录哪些视图。话虽如此,我可能会调整我的组件,因为 Google 会以不同的方式跟踪它。谢谢。
【解决方案5】:

请注意,如果您使用来自 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 component 只是路由器对象的一个​​非常薄的包装器。我们在这里使用&lt;Router history={history}&gt; 重新创建 BrowserRouter 功能,其中const history = createBrowserHistory();

【讨论】:

  • 你从不调用initGA?
  • @MuhammadUmer 是的,刚刚修好了
  • 为什么不在静态 HTML 中添加 GA?我加了你。因为我认为听历史对象是正确的方法。
  • @VinceV。您可以想象在您的构建中初始化history 对象,然后将历史记录存储在window 对象上并在您的&lt;head&gt; 的脚本标签中访问它,但我认为这最终会使您的构建管道更加复杂。 ¯_(ツ)_/¯
  • 如果您使用的是 BrowserRouter 组件,请参阅下面提供替代解决方案的答案。
【解决方案6】:

我建议使用出色的 react-router-ga 包,它非常轻巧且易于配置,尤其是在使用 BrowserRouter 包装器时。

导入组件:

import Analytics from 'react-router-ga';

然后只需在您的BrowserRouter 中添加&lt;Analytics&gt;

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

【讨论】:

  • 如果用户只想跟踪页面浏览量,这似乎是一个超级简单的解决方案。很瘦!
【解决方案7】:

我喜欢 Mark Thomas Müller 的建议 here

在你的 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>
        )
    }
}

简短、可扩展且简单:)

【讨论】:

  • 为什么会有跟踪,一个全局,一个本地?
【解决方案8】:

始终遵循图书馆推荐的方式

在 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;

【讨论】:

  • 如果我使用 SSR(服务器端渲染),GA 不刷新页面不知道实际页面的标题。
  • 您可以使用 React 更改挂载时的标题
  • 感谢发帖!
  • store 来自哪里?
  • ProviderConnectedRouter 来自哪里?这是一个不完整的答案,应该被否决
【解决方案9】:

这是一种通过一些变通方法跟踪所有路径的最简单方法:

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

然后将其导入到设置Router的位置

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

【讨论】:

    【解决方案10】:

    首先,在你的 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)};
    }
    

    【讨论】:

    • 这里使用的是哪个路由器版本?
    • 它用于反应路由器 dom v2 或 v3,而不是 v4
    【解决方案11】:

    我建议使用 Segment 分析库并按照 React quickstart guide 使用 react-router 库跟踪页面调用。您可以允许&lt;Route /&gt; 组件在页面呈现时进行处理,并使用componentDidMount 来调用page 调用。下面的示例显示了您可以执行此操作的一种方法:

        const App = () => (
          <div>
            <Switch>
              <Route exact path="/" component={Home} />
              <Route path="/about" component={About} />
            </Switch>
          </div>
        );
    
        export default App;
    
        export default class Home extends Component {
          componentDidMount() {
            window.analytics.page('Home');
          }
    
          render() {
            return (
              <h1>
                Home page.
              </h1>
            );
          }
        }
    

    我是https://github.com/segmentio/analytics-react 的维护者。如果您有兴趣尝试多种分析工具(我们支持超过 250 多个目的地),而无需编写任何额外代码,您可以通过 Segment 来打开和关闭不同的目的地。 ?

    【讨论】:

    • 此库已被弃用
    【解决方案12】:

    如果您使用哈希或浏览器历史记录,您可以这样做:

    import trackingHit from 'tracking';
    
    import { Router, browserHistory } from 'react-router';
    browserHistory.listen(trackingHit);
    // OR
    import { Router, hashHistory } from 'react-router';
    hashHistory.listen(trackingHit);
    

    在哪里 ./tracking.es6

    export default function(location) {
        console.log('New page hit', location.pathname);
        // Do your shizzle here
    }
    

    【讨论】:

      【解决方案13】:

      用你的 index.js 实现基本的 react-ga

      var ReactGA = require('react-ga'); // require the react-ga module
      ReactGA.initialize('Your-UA-ID-HERE'); // add your UA code 
      
      function logPageView() { // add this function to your component
        ReactGA.set({ page: window.location.pathname + window.location.search });
        ReactGA.pageview(window.location.pathname + window.location.search);
      }
      
      React.render((
      <Router history={createBrowserHistory()} onUpdate={logPageView} > // insert onUpdate props here
          <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'));
      

      【讨论】:

      • @BigDong 我不知道 closeHeader 是什么。你必须问 OP 这个问题,因为渲染代码是他的。我只是在展示如何为他的代码实现 react-ga(查找我的 // cmets)
      【解决方案14】:

      基于@david-l-walsh 和@bozdoz 的建议

      我创建了一个执行 window.ga('set','page','{currentUrl})window.ga('send', 'pageview'); 函数的 HOC,并且可以直接在路由器页面中轻松使用...

      这是 HOC:

      import React from 'react';
      import { history } from '../../store'; // or wherever you createBrowserHistory(); invokation is
      
      function withGAHistoryTrack(WrappedComponent) {
        return class extends React.Component {
          constructor(props) {
            super(props);
          }
      
          componentDidMount() {
            const { location } = history;
            const page = location.pathname + location.search;
      
            if (typeof window.ga === 'function') {
              window.ga('set', 'page', page);
              window.ga('send', 'pageview');
            }
          }
      
          render() {
            return <WrappedComponent {...this.props} />;
          }
        };
      }
      
      export default withGAHistoryTrack;
      

      并且在路由器页面中是这样使用的:

      <Route
       path={'yourPath'}
       component={withGAHistoryTrack(yourComponent)}
       exact
      />
      

      【讨论】:

        【解决方案15】:

        对于某些事件(如 onClick 等)动态更新 url,可以使用以下方法:

         //Imports
         import ReactGA from "react-ga";
         import { createBrowserHistory } from "history";
        
         // Add following on some event, like onClick (depends on your requirement)
         const history = createBrowserHistory();
         ReactGA.initialize("<Your-UA-ID-HERE>");
         ReactGA.pageview(history.location.pathname);
        

        【讨论】:

          猜你喜欢
          相关资源
          最近更新 更多
          热门标签