Router: tracking pageviews

Created on 5 Jun 2018  路  4Comments  路  Source: reach/router

Is there a particular way navigation tracking should be done? I couldn't find anything about it in the docs, but looking through the source code I found a solution, but I don't think it's ideal.

What I ended up doing was writing a component NavigationTracker.tsx that uses context.location from the Location component child callback.

import * as React from 'react';
import * as ReactGA from 'react-ga';

interface NavigationTrackerProps {
  pathname: string;
  children?: React.ReactNode;
}

export default class NavigationTracker extends React.Component<
  NavigationTrackerProps
> {
  componentDidMount() {
    this.pageview(this.props.pathname);
  }

  componentDidUpdate(prevProps: NavigationTrackerProps) {
    if (this.props.pathname !== prevProps.pathname) {
      this.pageview(this.props.pathname);
    }
  }

  pageview(pathname: string) {
    ReactGA.set({ page: pathname });
    ReactGA.send({ hitType: 'pageview' });
  }

  render(): React.ReactNode {
    return this.props.children || null;
  }
}


In use it looks like:

<LocationProvider>
  <Router>
    {...routes}
  </Router>
  <Location
    children={context => (
      <NavigationTracker pathname={context.location.pathname} />
    )}
  />
</LocationProvider>

If it turns out this has not been accounted for, I'm happy to give it a shot if I get some guidance on how it should be built.

To start it off, I guess what I'd like to see is something like:

<Router onChange={location => {/* do whatever */}}>
  {...routes}
</Router>

alternatively just exposing the history.listen function.

EDIT: First version of NavigationTracker.tsx didn't work as expected

Most helpful comment

Yep, I've got something like this in my app:

import Component from '@reactions/component'

const track = pathname => { /* ... */ }

const TrackPageViews = () => (
  <Location>
    {({ location }) => (
      <Component
        location={location}
        didMount={() => track(location.pathname)}
        didUpdate={({ prevProps }) => {
          if (prevProps.location !== location) {
            track(location.pathname)
          }
        }}
      />
    )}
  </Location>
)

All 4 comments

history.listen is available outside of the React component tree via createHistory: https://reach.tech/router/api/createHistory

But your NavigationTracker is correct and ideal. I'd got with that.

Yep, I've got something like this in my app:

import Component from '@reactions/component'

const track = pathname => { /* ... */ }

const TrackPageViews = () => (
  <Location>
    {({ location }) => (
      <Component
        location={location}
        didMount={() => track(location.pathname)}
        didUpdate={({ prevProps }) => {
          if (prevProps.location !== location) {
            track(location.pathname)
          }
        }}
      />
    )}
  </Location>
)

Excellent, thanks :)

Usage:

const App = () => (
  <div>
    <TrackPageViews/>
    <Router>
      {/* ... */}
    </Router>
  </div>
)
Was this page helpful?
0 / 5 - 0 ratings

Related issues

magnusarinell picture magnusarinell  路  3Comments

ricardobrandao picture ricardobrandao  路  5Comments

jsonmaur picture jsonmaur  路  4Comments

kbrgl picture kbrgl  路  4Comments

alexandernanberg picture alexandernanberg  路  3Comments