Giter Club home page Giter Club logo

react-metrics's People

Contributors

alanmulhall avatar doctyper avatar jamsea avatar ldeavila avatar mmairs9 avatar nmoore93 avatar potench avatar taak77 avatar wmartins avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-metrics's Issues

Custom vendor API methods require an argument to be passed

When creating a custom method (as outlined here: https://github.com/nfl/react-metrics/blob/master/docs/Guides.md#api) the method always expects an argument to be passed, whether or not the method expects one. To recreate the issue, use the example in the docs, and use the metrics context object to call the method (i.e - this.context.metrics.someMethod()).
When no argument is passed, the method doesn't get called, but if anything is passed, the method gets called.

Using metrics in redux-middleware in addition to @metrics(config) on root component causes `pageView` payload to contain some fields from `track`

I've got react-metrics set up with a React + Redux application. The analytics provider in use is Adobe Tag Manager (Omniture), and the configuration provided in the example was used.

I've got automatic pageView tracking enabled by decorating the react-router routes component with @metrics. I've verified that the correct payload is being sent in the Network debugger. However, when I set up a redux-middleware to track customLinks, the payload sent in the pageView call (from the earlier @metrics) now contains fields set in the track call in middleware.

This is what the middleware looks like -

const analyticsMiddleware = ({getState}) => {
	return next => action => {
		const returnValue = next(action);
		let payload;
		switch (action.type) {
			default:
				if (analyticsUtils.whitelist.has(action.type)) {
					payload = {
                                              abc: 'abc',
                                        }
					metrics.api.track('customLink', payload);
				}
		}
		return returnValue;
	};
};

The pageView calls now have the key abc (can be seen as a query param in network inspector), even though abc is only set in the track call in middleware.

Invariant Violation: `metrics` should only be added once to the root level component. You have added to both App and App.

Hi,

Here are some lines of my unit test code that generate an Invariant Violation:

// src/app.js
@metrics(metricsConfig, metricsOptions)
class App extends Component {
  ...
}

export default App
// src/app.spec.js
describe('App ', () => {
  it('should shallow render Hello', () => {
    const tree = shallow(<App children="Hello" />)
    expect(tree).toMatchSnapshot()
  })

  it('should shallow render World', () => {
    const tree = shallow(<App children="World" />)
    expect(tree).toMatchSnapshot()
  })
})

When I run the tests, I have this error:

Invariant Violation: `metrics` should only be added once to the root level component. You have added to both App and App.

  at invariant (node_modules/fbjs/lib/invariant.js:44:15)
  at MetricsContainer.componentWillMount (node_modules/react-metrics/lib/react/metrics.js:94:49)
  at node_modules/react-test-renderer/lib/shallow/ReactCompositeComponent.js:348:23
  at measureLifeCyclePerf (node_modules/react-test-renderer/lib/shallow/ReactCompositeComponent.js:75:12)
  at ShallowComponentWrapper.performInitialMount (node_modules/react-test-renderer/lib/shallow/ReactCompositeComponent.js:347:9)
  at ShallowComponentWrapper.mountComponent (node_modules/react-test-renderer/lib/shallow/ReactCompositeComponent.js:258:21)
  at Object.mountComponent (node_modules/react-test-renderer/lib/shallow/ReactReconciler.js:46:35)
  at ReactShallowRenderer._render (node_modules/react-test-renderer/lib/shallow/ReactShallowRenderer.js:138:23)
  at _batchedRender (node_modules/react-test-renderer/lib/shallow/ReactShallowRenderer.js:85:12)
  at Object.batchedUpdates (node_modules/react-test-renderer/lib/shallow/ReactDefaultBatchingStrategy.js:60:14)
  at Object.batchedUpdates (node_modules/react-test-renderer/lib/shallow/ReactUpdates.js:97:27)
  at ReactShallowRenderer.render (node_modules/react-test-renderer/lib/shallow/ReactShallowRenderer.js:112:18)
  at ReactShallowRenderer.render (node_modules/enzyme/build/react-compat.js:180:39)
  at node_modules/enzyme/build/ShallowWrapper.js:128:26
  at ReactDefaultBatchingStrategyTransaction.perform (node_modules/react-test-renderer/lib/shallow/Transaction.js:140:20)
  at Object.batchedUpdates (node_modules/react-test-renderer/lib/shallow/ReactDefaultBatchingStrategy.js:62:26)
  at Object.batchedUpdates (node_modules/react-test-renderer/lib/shallow/ReactUpdates.js:97:27)
  at ReactShallowRenderer.unstable_batchedUpdates (node_modules/react-test-renderer/lib/shallow/ReactShallowRenderer.js:130:25)
  at performBatchedUpdates (node_modules/enzyme/build/ShallowWrapper.js:103:21)
  at node_modules/enzyme/build/ShallowWrapper.js:127:9
  at withSetStateAllowed (node_modules/enzyme/build/Utils.js:284:3)
  at new ShallowWrapper (node_modules/enzyme/build/ShallowWrapper.js:126:38)
  at shallow (node_modules/enzyme/build/shallow.js:19:10)
  at shallow (jest/__mocks__/enzyme.js:133:30)
  at Object.<anonymous> (src/__tests__/App.spec.js:22:36)
  at Promise.resolve.then.el (node_modules/p-map/index.js:42:16)
  at process._tickCallback (internal/process/next_tick.js:109:7)

This is because the variable mountedInstances is never reset.
I believe this variable is encapsulated in a closure and is not garbage collected.

What solutions do we have to test this main app component?

Thank you for your help

Should have option to have event bubble to parent link

If I have, for example:

<a data-metrics-event-name="SomeEvent">
  <img src="..." />
</a>

and the user clicks on the image... the events won't register because the event.target is the image and has no data-metrics. There should be an option or something to fix this to have it bubble to data-metrics. I have this problem here:

return (
      <Link to={this.getPath()}>
        <h4>
          <u
            data-metrics-event-name="ActivityRow:Title:Click"
            data-metrics-activity-id={activity.id}>
            {/* LEGACY */}
            {activity.infoName || activity.name}
          </u>
        </h4>
      </Link>
    );

which is bad cause the <u> tag should not have the event names.

Provide a 'withMetrics' HOC to abstract react context

The catalyst of this request comes from me stumbling across this from Dan Abramov: https://twitter.com/dan_abramov/status/749715530454622208

Backing this up, the react docs recommend not to use the context directly https://facebook.github.io/react/docs/context.html#why-not-to-use-context

I propose a "withMetrics" higher order component that accepts a react-redux style 'mapMetricsToProps' function to map metrics API functions to a components props.

import React from 'react';
import { withMetrics } from 'react-metrics';

class TopCheckoutButton extends React.Component {
 render() {
  const { trackCheckout } = this.props;
  return <button onClick={() => trackCheckout('top')} />;
 }
}

class BottomCheckoutButton extends React.Component {
 render() {
  const { trackCheckout } = this.props;
  return <button onClick={() => trackCheckout('bottom')} />;
 }
}

function trackCheckoutEvent(metrics) {
 return (checkoutButtonPosition) => {
  return metrics.track(`checkout_${checkoutButtonPosition}`);
 };
}

function mapMetricsToProps(metrics) {
 return {
  trackCheckout: trackCheckoutEvent(metrics)
 }
}

const TrackedTopCheckoutButton = withMetrics(mapMetricsToProps)(TopCheckoutButton);
const TrackedBottomCheckoutButton = withMetrics(mapMetricsToProps)(BottomCheckoutButton);

export TrackedTopCheckoutButton;
export TrackedBottomCheckoutButton;

The above example demonstrates the usage of such a HOC to compose tracked checkout buttons using a common curried function that wraps the track() call from react-metrics.

A more simplistic example would be exposing the react-metrics API functions directly to the wrapped component

export default withMetrics(metrics => { trackSomething: metrics.track })(MyTrackedComponent); // Named tracking methods
export default withMetrics()(MyOtherTrackedComponent); // Default passing all react-metrics api functions as props

Interested to know if this feature sounds reasonable to implement directly into this repository and if you would accept PRs for such a feature.

metrics decorator and unit-testing

Hi,

the metrics decorator is not very unit-test friendly. It allows mounting a component only once and remembers the instance on a global variable relative to the module.
There is no API to reset the instances right now, isn't it? Not even unmounting will help.

Please add a sane way to clear test cases.

Reduce `polyfill.js` or remove all together

I have noticed you are importing the polyfill.js into this package which bloats the file size when you use it in a project. I would much prefer giving people the option to use their own polyfills if they need them for their projects.

At least remove the promise polyfill which adds 10kb. Add to the readme about the need to use your own promise polyfill.

side note
Ideally there will be better support for having ES5 and ES2015 npm modules together. Something like rollup has. So once webpack v2 is released then we can all do tree-shaking.

Possible to use with es5 / React.createClass?

Hi. I'm working on a React project that is mixed ES5/ES6 and still uses React.createClass for creation of components. Is it possible to use the react-metrics package while using createClass for components?

Handling Malformed URI

Currently react-metrics throws an exception on this line when the site URI is malformed with an invalid query string:
https://github.com/nfl/react-metrics/blob/master/src/core/createMetrics.js#L13

Ideally, querystring.decode would be wrapped in a try/catch, spit the error out in the console and set qs to {} so that the site doesn't partially render due to the unhandled js exception.

We are also trying to correct the invalid query string coming into our site, but we ideally would still render a working site even if the query string is malformed.

inherit parent data attributes for tracking

Is there any way to inherit higher level component or parent elements data-attributes to its children so I don't have to duplicate data attributes throughout the codebase?

I was able to create a PR but it broke some of the tests. Basically instead of traversing through the next specified root element (MetricsElement) it will traverse to the root Dom element on document body. It will then add any parent data attributes to the existing track call. Lower level attributes will override their parent as it is closer to the source of the click tracking.

analytics.js and key

Hey, using Segment as suggested in the docs, how did you figure out getting your Segment write key into the vendors?

Thanks!

Working example with NextJS

Do you have an example for a site that supports SSR? I am using NextJS and I am not able to limit importing the vendor/GoogleAnalytics.js class to only client side rendering. How do I replace the GoogleAnalyticsStub below to get this working?

metrics.config.js

import { ga } from 'client-config'
import GoogleAnalytics from '../lib/GoogleAnalytics'

const MetricsConfig = {
  vendors: [{
    name: 'Google Analytics',
    api: new GoogleAnalytics({
      trackingId: ga.tracking_id
    })
  }],
  pageViewEvent: 'pageLoad',
  pageDefaults: () => {
    return {
      environment: ga.environment,
      siteName: ga.siteName,
      timestamp: Date.now(),
      path: '/'
    }
  },
  debug: ga.debug
}

export default MetricsConfig

Layout.js

import React from 'react'
import pageLoadTracking from '../lib/pageLoadTracking'

const Layout = ({ children }) => (
  <Main>
    {children}
  </Main>
)

export default pageLoadTracking(Layout)

package.json

 "dependencies": {
    "above-the-fold-only-server-render": "^1.0.3",
    "analytics.js": "^2.9.1",
    "config": "^1.25.1",
    "express": "^4.15.2",
    "js-yaml": "^3.8.3",
    "mkdirp": "^0.5.1",
    "next": "^2.3.1",
    "next-routes": "^1.0.26",
    "prop-types": "^15.5.8",
    "react": "^15.5.4",
    "react-apollo": "^1.2.0",
    "react-dom": "^15.5.4",
    "react-ga": "^2.2.0",
    "react-gpt": "^0.2.4",
    "react-metrics": "^2.3.1",
    "react-no-ssr": "^1.1.0",
    "styled-components": "^1.4.5"
  },
  "devDependencies": {
    "babel-eslint": "^7.2.3",
    "babel-plugin-module-resolver": "^2.7.0",
    "babel-preset-es2015": "^6.24.1",
    "babel-preset-stage-0": "^6.24.1",
    "babel-register": "^6.24.1",
    "chai": "^3.5.0",
    "enzyme": "^2.8.2",
    "ignore-styles": "^5.0.1",
    "jsdom": "^9.12.0",
    "lighthouse": "^1.6.3",
    "mocha": "^3.2.0",
    "nightwatch": "^0.9.14",
    "phantomjs-prebuilt": "^2.1.14",
    "react-test-renderer": "^15.5.4",
    "selenium-server": "^3.3.1",
    "sinon": "^2.1.0",
    "standard": "^10.0.1"
  },

GoogleAnalytics.js

let analytics
if (process.browser) {
  analytics = require('analytics.js') // eslint-disable-line global-require
}

/**
 * Performs the tracking calls to Google Analytics.
 * Utilizing Segment IO Analytics Integration.
 *
 * @module GoogleAnalytics
 * @class
 * @internal
 */
class GoogleAnalytics {
  constructor (options = {}) {
    this.name = 'Google Analytics'
    this._loaded = false
    this.options = options
  }
  /**
   *
   * @method pageView
   * @param {String} eventName
   * @param {Object} params
   * @returns {Promise}
   * @internal
   */
  pageView (...args) {
    return this.track(...args)
  }
  user (userId) {
    return new Promise((resolve) => {
      this.userId = userId
      resolve({
        userId
      })
    })
  }
  /**
   *
   * @method track
   * @param {String} eventName
   * @param {Object} params
   * @returns {Promise}
   * @internal
   */
  track (eventName, params) {
    return new Promise((resolve, reject) => {
      this._load().then(() => {
        this._track(eventName, params)
        resolve({
          eventName,
          params
        })
      }).catch((error) => {
        console.error('GA: Failed to initialize', error)
        reject(error)
      })
    })
  }
  /**
   *
   * @method _track
   * @param {String} eventName
   * @param {Object} params
   * @protected
   */
  _track (eventName, params) {
    if (eventName === 'pageView') {
      analytics.page(params.category, params)
      return
    }
    analytics.track(eventName, params)
  }
  /**
   *
   * @method _load
   * @protected
   */
  _load () {
    return this._promise || (this._promise = new Promise((resolve) => {
      if (this._loaded) {
        resolve()
      } else {
        analytics.once('ready', () => {
          this._loaded = true
          resolve()
        })
        analytics.initialize({
          'Google Analytics': this.options
        })
      }
    }))
  }
}

export default GoogleAnalytics

Error in Router basic example

Hi there,

I've just cloned the repo and am running the examples. Everything works fine except for the React Router / Basic Example. Clicking on the "Basic Example" link gives the following error:

Uncaught TypeError: (0 , _reactMetrics2.default) is not a function
    at Object.677 (react-router_basic.js:4716)
    at __webpack_require__ (bootstrap 114f31eaf14d44e3980b:52)
    at Object.628 (app.js:17)
    at __webpack_require__ (bootstrap 114f31eaf14d44e3980b:52)
    at Object.0 (react-router_basic.js:8)
    at __webpack_require__ (bootstrap 114f31eaf14d44e3980b:52)
    at webpackJsonpCallback (bootstrap 114f31eaf14d44e3980b:23)
    at react-router_basic.js:1

Given I didn't do anything other than npm install, npm run examples I hope that is enough for you. Otherwise let me know if you need more info.

Warning when accessing PropTypes via main package

Hey guys, first of all, thank you for this awesome library.

I'm opening this issue because we noticed a common problem when using this library with React v15.5.0.

Currently, react-metrics is displaying the following warning on console:

Warning: Accessing PropTypes via the main React package is deprecated. Use the prop-types package from npm instead.

As of React v15.5.0, PropTypes has its own package, and now it shows a deprecation warning when using PropTypes directly from React package.

Related: https://facebook.github.io/react/blog/2017/04/07/react-v15.5.0.html#new-deprecation-warnings

Just as a quick reference, this code now shows a warning:

import { PropTypes } from 'react';

Now, the "correct" way of using PropTypes is via prop-types package.

import PropTypes from 'prop-types';

Do you guys mind if I open a pull request to use this new prop-types package instead of "main" PropTypes?

Thank you!


Related: #38

enabled=false in config not working

There is logic in the code, if there is no any venders disable metrics with enabled:false, but after this it returns error react-metrics: 'pageView' api needs to be defined for automatic page view tracking. from https://github.com/nfl/react-metrics/blob/master/src/react/metrics.js#L143. I guess, this line of code should check whether metrics enabled or not.

Audit issue with node-fetch

Hi,
react-metrics is the last package on the a list of updates to nested packages to solve an issue with node-fetch.
image
Could someone take a look at this please?
Cheers!

Support react-router v4

Hi,
First thanks for this great library!

Is react-metrics supports react-router4?

If no is there any plan/timeline for this?
If yes, is there anything special need to be done?

Thanks!
Gilad

Add Ability for keypress and hover tracking with data attributes

Enhancement request. Would love to be able to have a data attribute that could trigger an element to be tracked when key pressing (enter key) or hovering over an element for a duration of time. This would pretty much allow us to keep all of our tracking code in data attributes.

SVG click in IE logs a 'Unable to get property 'attributes' of undefined or null reference' console error

Hi, this issue only occurs in IE. When clicking on an SVG icon in IE that is to be tracked through the use of , or is in a section to be tracked, an error is logged in the console stating that 'Unable to get property 'attributes' of undefined or null reference'.

It seems that element.parentElement is not supported for SVG elements in IE so needs to also use element.parentNode.

I have a PR ready to add as well which I will link to this issue.

Thanks.

Does this support Average time on page?

Essentially I am looking to build out my own metrics system to track performance of a widget embedded externally from my main application. Currently, the way that it works is I have an iFrame with a specific path for each widget and then I use Google Analytics's API to get data on those paths (pageviews and average time on page) but it's a pain in the ๐Ÿ‘

I am looking for a solution where I can build out a component that tracks it's own performance without relying on a URL path - ie if someone embeds my widget somewhere without an iFrame, I want the component to be able to track it's own data and push it down to my DB.

I can imagine I'd be able to do so for pageviews but I don't see any documentation on average time on page.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.