Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

react-tracker

Package Overview
Dependencies
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-tracker - npm Package Compare versions

Comparing version
0.0.3
to
0.0.4
+247
README.md
# ![React tracker Logo](http://pichoster.net/images/2018/01/07/32e65824cf5bdee238722112b9e95a10.png)
# react-tracker [![npm version](https://badge.fury.io/js/react-tracker.svg)](https://badge.fury.io/js/react-tracker)
- React specific tracking library, usable as a higher-order component
- Flexible-scalable solution for tracking in React Apps
- Easy to use (Redux-like)
- Can be pluged with any Analytics platform agnostic lib (You can mainly do anything in the event listeners callback)
## Installation
```
npm install --save react-tracker
```
This assumes you are using [npm](https://www.npmjs.com/) as your package manager.
## The Gist
The idea is to only provide one Tracker!
Why? because at some you'll need to apply some restriction on some events E.g. :
- Track product click only once!
- Track product click only if page views is already tracked
in these case we need to have the tracking history.. that's why we keep the history synced by providing the **same instance of tracker to all components**
```js
import { Tracker } from 'react-tracker';
/**
* This is an event listner, a pure function with (event, eventsHistory) => tracking goes here.
* It describes what to do with the just-fired event.
*
* There is two types of event listeners
* 1- Listener with eventType specified it will be called when the given eventType is fired/dispatched
* 2- Listener with no eventType it will be called whenevent an event fired/dispatched
* Think of the last type of listeners as `jQuery.on('*', callback)`
* You can use `switch` statement to handle multiple events in one listener
*/
// Listener-per-event example
function trackAddToCartClick(event = {}, eventsHistory) {
if (event.type) {
// Call GTM or you tracking provider...
// If you want save this event, just return it, otherwise it will be ignored.
return event
}
}
// Allow `trackAddToCartClick` to listen only on `ADD_TO_CART_BUTTON_CLICK` event!
trackAddToCartClick.eventType = 'ADD_TO_CART_BUTTON_CLICK';
// Listen-on-all example
function trackCartEvents(event = {}, eventsHistory) {
switch(event.type) {
case 'ADD_TO_CART_BUTTON_CLICK':
// CALL your tracking provider..
// If you want save this event, just return it, otherwise it will be ignored.
return event
case 'REMOVE_FROM_CART_CLICK':
// Your tracking logic goes here..
break;
default:
// silence
}
// Create a Tracker holding the tracked events History of your app.
// Its API is { on, trackEvent, getHistory }.
let tracker = new Tracker([trackAddToCartClick, trackCartEvents])
// In additional to to intialize the tracker with event listeners.
// You can add a an event listener using `on()`
// Listen on `PRODUCT_CLICK`events.
tracker.on('PRODUCT_CLICK', (event, eventsHistory) =>
console.log(event)
);
// Listen on all events
tracker.on('*', (event, eventsHistory) =>
console.log(event)
);
// And then you can fire an events using `trackEvent` function :
// Fire `ADD_TO_CART_EVENT`
tracker.trackEvent({ type: 'ADD_TO_CART_EVENT' })
// Fire `ADD_TO_CART_EVENT`
tracker.trackEvent({ type: 'ADD_TO_CART_EVENT' })
// Fire `PRODUCT_CLICK`
tracker.trackEvent({ type: 'PRODUCT_CLICK' })
```
## Usage with React
#### `components/Product.js`
```js
import React from 'react'
import PropTypes from 'prop-types'
const Product = ({ onClick, title, price, currency }) => (
<li
onClick={onClick}
>
{title}
<span> {price} {currency} </span>
</li>
)
Product.propTypes = {
onClick: PropTypes.func.isRequired,
title: PropTypes.bool.isRequired,
price: PropTypes.string.isRequired
currency: PropTypes.string.isRequired
}
export default Product
```
#### `components/ProductList.js`
```js
import React from 'react'
import PropTypes from 'prop-types'
import Product from './Product'
const ProductList = ({ products, trackProductClick }) => (
<ul>
{products.map(product => (
<Product key={product.id} {...product} onClick={() => trackProductClick(product.id, product.price)} />
))}
</ul>
)
ProductList.propTypes = {
products: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.number.isRequired,
title: PropTypes.string.isRequired,
price: PropTypes.string.isRequired,
currency: PropTypes.string.isRequired,
}).isRequired
).isRequired,
trackProductClick: PropTypes.func.isRequired
}
export default ProductList
```
### Implementing Container Components
Now it's tracking time..
To use `withTracking()`, you need to define a special function (react-redux-like) called `mapTrackingToProps` that tells how to pass the trackEvent function to the props.
For example, we need to track product click with Product ID and price, so we need to fire the event on the procut click!
!!!! as we know the `trackEvent` only accpect the object that describes the Event (type and data if any) !!!!
#### `.../tracking/listeners/cart.js`
```js
function trackProductClick(event = {}, eventsHistory) {
if (event.type) {
// Call GTM or you tracking provider...
// If you want save this event, just return it, otherwise it will be ignored.
return event
}
}
// scope `trackProductClick` to listen only on `PRODUCT_CLICK` event!
trackProductClick.eventType = 'PRODUCT_CLICK';
```
#### `.../tracking/events/cart.js`
```js
function getProductClickEvent(id, price) {
return {
type: 'PRODUCT_CLICK',
data: {
id: id,
price: price
}
}
};
```
```js
const mapTrackingToProps = trackEvent => {
return {
trackProductClick: (id, price) => {
trackEvent(getProductClickEvent(id, price))
}
}
}
```
Finally, we create the `ProductsList` by calling `withTracking()` and passing our `mapTrackingToProps`:
```js
import { withTracking } from 'react-tracker'
const ProductsListWithTracking = withTracking(mapDispatchToProps)(ProductsList)
export default ProductsListWithTracking
```
## Let React meet our Tracker
All container components need access to the tracker so they can fire events.
We will use the `<Provider>` to [magically](https://facebook.github.io/react/docs/context.html) make the tracker available to all container components in the application without passing it explicitly.
You only need to use it once when you render the root component:
#### `index.js`
```js
import React from 'react'
import { render } from 'react-dom'
import { TrackerProvider, Tracker } from 'react-tracker'
import { trackProductClick } from './tracking/listeners/cart'
import ProductsList from './components/ProductsList'
let store = new Tracker([trackProductClick /*, other event listeners goes here*/])
render(
<TrackerProvider tracker={store}>
<ProductsList products={someProducts} />
</TrackerProvider>,
document.getElementById('root')
)
```
## Contribution
This project is in its early stages, I'd be very happy if you can help :)
## License
MIT
+1
-1
{
"name": "react-tracker",
"version": "0.0.3",
"version": "0.0.4",
"description": "Track actions within your React app with a tracker redux-like!",

@@ -5,0 +5,0 @@ "main": "build/index.js",

!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.ReactTracker=t():e.ReactTracker=t()}("undefined"!=typeof self?self:this,function(){return function(e){function t(n){if(r[n])return r[n].exports;var o=r[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var r={};return t.m=e,t.c=r,t.d=function(e,r,n){t.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:n})},t.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(r,"a",r),r},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="build/",t(t.s=4)}([function(e,t,r){"use strict";e.exports=r(6)},function(e,t,r){"use strict";function n(e){return function(){return e}}var o=function(){};o.thatReturns=n,o.thatReturnsFalse=n(!1),o.thatReturnsTrue=n(!0),o.thatReturnsNull=n(null),o.thatReturnsThis=function(){return this},o.thatReturnsArgument=function(e){return e},e.exports=o},function(e,t,r){"use strict";var n=r(9),o=r.n(n);t.a=(Object.assign||function(e){for(var t=1;arguments.length>t;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e})({},o.a,{tracker:o.a.shape({subscribe:o.a.func.isRequired,dispatch:o.a.func.isRequired})})},function(e,t,r){"use strict";r.d(t,"b",function(){return n}),r.d(t,"a",function(){return o});var n=function(e){return"TrackEventProvider("+(e.displayName||e.name||"Component")+")"},o=function(){return(arguments.length>0&&void 0!==arguments[0]?arguments[0]:[]).map(function(e){var t=Object.keys(e)[0];if(t&&"function"==typeof e[t])return e[t].eventType=t,e[t]}).filter(function(e){return!!e})}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(5),o=r(13),i=r(14);r.d(t,"Tracker",function(){return i.a}),r.d(t,"TrackerProvider",function(){return n.a}),r.d(t,"provideTrackEvent",function(){return o.a})},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function i(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var u=r(0),c=(r.n(u),r(2)),a=function(){function e(e,t){for(var r=0;t.length>r;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}return function(t,r,n){return r&&e(t.prototype,r),n&&e(t,n),t}}(),f=function(e){function t(e,r){n(this,t);var i=o(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,r));return i.tracker=e.tracker,i}return i(t,e),a(t,[{key:"getChildContext",value:function(){return{trackEvent:this.tracker.dispatch}}}]),a(t,[{key:"render",value:function(){return u.Children.only(this.props.children)}}]),t}(u.Component);t.a=f,f.propTypes={children:c.a.element.isRequired},f.childContextTypes={trackEvent:c.a.func.isRequired}},function(e,t,r){"use strict";function n(e){for(var t=arguments.length-1,r="Minified React error #"+e+"; visit http://facebook.github.io/react/docs/error-decoder.html?invariant="+e,n=0;t>n;n++)r+="&args[]="+encodeURIComponent(arguments[n+1]);throw t=Error(r+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."),t.name="Invariant Violation",t.framesToPop=1,t}function o(e,t,r){this.props=e,this.context=t,this.refs=g,this.updater=r||R}function i(e,t,r){this.props=e,this.context=t,this.refs=g,this.updater=r||R}function u(){}function c(e,t,r){this.props=e,this.context=t,this.refs=g,this.updater=r||R}function a(e,t,r){var n,o={},i=null,u=null;if(null!=t)for(n in void 0!==t.ref&&(u=t.ref),void 0!==t.key&&(i=""+t.key),t)A.call(t,n)&&!q.hasOwnProperty(n)&&(o[n]=t[n]);var c=arguments.length-2;if(1===c)o.children=r;else if(c>1){for(var a=Array(c),f=0;c>f;f++)a[f]=arguments[f+2];o.children=a}if(e&&e.defaultProps)for(n in c=e.defaultProps)void 0===o[n]&&(o[n]=c[n]);return{$$typeof:j,type:e,key:i,ref:u,props:o,_owner:C.current}}function f(e){return"object"==typeof e&&null!==e&&e.$$typeof===j}function s(e){var t={"=":"=0",":":"=2"};return"$"+(""+e).replace(/[=:]/g,function(e){return t[e]})}function l(e,t,r,n){if(I.length){var o=I.pop();return o.result=e,o.keyPrefix=t,o.func=r,o.context=n,o.count=0,o}return{result:e,keyPrefix:t,func:r,context:n,count:0}}function p(e){e.result=null,e.keyPrefix=null,e.func=null,e.context=null,e.count=0,10>I.length&&I.push(e)}function y(e,t,r,o){var i=typeof e;"undefined"!==i&&"boolean"!==i||(e=null);var u=!1;if(null===e)u=!0;else switch(i){case"string":case"number":u=!0;break;case"object":switch(e.$$typeof){case j:case _:case w:case x:u=!0}}if(u)return r(o,e,""===t?"."+h(e,0):t),1;if(u=0,t=""===t?".":t+":",Array.isArray(e))for(var c=0;e.length>c;c++){i=e[c];var a=t+h(i,c);u+=y(i,a,r,o)}else if(null===e||void 0===e?a=null:(a=E&&e[E]||e["@@iterator"],a="function"==typeof a?a:null),"function"==typeof a)for(e=a.call(e),c=0;!(i=e.next()).done;)i=i.value,a=t+h(i,c++),u+=y(i,a,r,o);else"object"===i&&(r=""+e,n("31","[object Object]"===r?"object with keys {"+Object.keys(e).join(", ")+"}":r,""));return u}function h(e,t){return"object"==typeof e&&null!==e&&null!=e.key?s(e.key):t.toString(36)}function d(e,t){e.func.call(e.context,t,e.count++)}function b(e,t,r){var n=e.result,o=e.keyPrefix;e=e.func.call(e.context,t,e.count++),Array.isArray(e)?v(e,n,r,k.thatReturnsArgument):null!=e&&(f(e)&&(t=o+(!e.key||t&&t.key===e.key?"":(""+e.key).replace($,"$&/")+"/")+r,e={$$typeof:j,type:e.type,key:t,ref:e.ref,props:e.props,_owner:e._owner}),n.push(e))}function v(e,t,r,n,o){var i="";null!=r&&(i=(""+r).replace($,"$&/")+"/"),t=l(t,i,n,o),null==e||y(e,"",b,t),p(t)}var m=r(7),g=r(8),k=r(1),O="function"==typeof Symbol&&Symbol.for,j=O?Symbol.for("react.element"):60103,_=O?Symbol.for("react.call"):60104,w=O?Symbol.for("react.return"):60105,x=O?Symbol.for("react.portal"):60106,P=O?Symbol.for("react.fragment"):60107,E="function"==typeof Symbol&&Symbol.iterator,R={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}};o.prototype.isReactComponent={},o.prototype.setState=function(e,t){"object"!=typeof e&&"function"!=typeof e&&null!=e&&n("85"),this.updater.enqueueSetState(this,e,t,"setState")},o.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")},u.prototype=o.prototype;var T=i.prototype=new u;T.constructor=i,m(T,o.prototype),T.isPureReactComponent=!0;var S=c.prototype=new u;S.constructor=c,m(S,o.prototype),S.unstable_isAsyncReactComponent=!0,S.render=function(){return this.props.children};var C={current:null},A=Object.prototype.hasOwnProperty,q={key:!0,ref:!0,__self:!0,__source:!0},$=/\/+/g,I=[],N={Children:{map:function(e,t,r){if(null==e)return e;var n=[];return v(e,n,null,t,r),n},forEach:function(e,t,r){if(null==e)return e;t=l(null,null,t,r),null==e||y(e,"",d,t),p(t)},count:function(e){return null==e?0:y(e,"",k.thatReturnsNull,null)},toArray:function(e){var t=[];return v(e,t,null,k.thatReturnsArgument),t},only:function(e){return f(e)||n("143"),e}},Component:o,PureComponent:i,unstable_AsyncComponent:c,Fragment:P,createElement:a,cloneElement:function(e,t,r){var n=m({},e.props),o=e.key,i=e.ref,u=e._owner;if(null!=t){if(void 0!==t.ref&&(i=t.ref,u=C.current),void 0!==t.key&&(o=""+t.key),e.type&&e.type.defaultProps)var c=e.type.defaultProps;for(a in t)A.call(t,a)&&!q.hasOwnProperty(a)&&(n[a]=void 0===t[a]&&void 0!==c?c[a]:t[a])}var a=arguments.length-2;if(1===a)n.children=r;else if(a>1){c=Array(a);for(var f=0;a>f;f++)c[f]=arguments[f+2];n.children=c}return{$$typeof:j,type:e.type,key:o,ref:i,props:n,_owner:u}},createFactory:function(e){var t=a.bind(null,e);return t.type=e,t},isValidElement:f,version:"16.2.0",__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED:{ReactCurrentOwner:C,assign:m}},U=Object.freeze({default:N}),F=U&&N||U;e.exports=F.default?F.default:F},function(e,t,r){"use strict";function n(e){if(null===e||void 0===e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}var o=Object.getOwnPropertySymbols,i=Object.prototype.hasOwnProperty,u=Object.prototype.propertyIsEnumerable;e.exports=function(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},r=0;10>r;r++)t["_"+String.fromCharCode(r)]=r;if("0123456789"!==Object.getOwnPropertyNames(t).map(function(e){return t[e]}).join(""))return!1;var n={};return"abcdefghijklmnopqrst".split("").forEach(function(e){n[e]=e}),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},n)).join("")}catch(e){return!1}}()?Object.assign:function(e,t){for(var r,c,a=n(e),f=1;arguments.length>f;f++){r=Object(arguments[f]);for(var s in r)i.call(r,s)&&(a[s]=r[s]);if(o){c=o(r);for(var l=0;c.length>l;l++)u.call(r,c[l])&&(a[c[l]]=r[c[l]])}}return a}},function(e,t,r){"use strict";var n={};e.exports=n},function(e,t,r){e.exports=r(10)()},function(e,t,r){"use strict";var n=r(1),o=r(11),i=r(12);e.exports=function(){function e(e,t,r,n,u,c){c!==i&&o(!1,"Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types")}function t(){return e}e.isRequired=e;var r={array:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t};return r.checkPropTypes=n,r.PropTypes=r,r}},function(e,t,r){"use strict";function n(e,t,r,n,i,u,c,a){if(o(t),!e){var f;if(void 0===t)f=Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var s=[r,n,i,u,c,a],l=0;f=Error(t.replace(/%s/g,function(){return s[l++]})),f.name="Invariant Violation"}throw f.framesToPop=1,f}}var o=function(e){};e.exports=n},function(e,t,r){"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},function(e,t,r){"use strict";var n=r(0),o=r.n(n),i=r(3),u=r(2),c=Object.assign||function(e){for(var t=1;arguments.length>t;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e};t.a=function(e,t){var r=Object(i.b)(e),n=function(t,n){var i=n.trackEvent;if(!i)throw Error('Could not find tracker in the context of "'+r+'"');var u=c({},t,{trackEvent:i});return o.a.createElement(e,u)};return n.displayName=r,n.contextTypes={trackEvent:u.a.func.isRequired},n}},function(e,t,r){"use strict";function n(e){if(Array.isArray(e)){for(var t=0,r=Array(e.length);e.length>t;t++)r[t]=e[t];return r}return Array.from(e)}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var i=r(3),u=function(){function e(e,t){for(var r=0;t.length>r;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}return function(t,r,n){return r&&e(t.prototype,r),n&&e(t,n),t}}();t.a=function(){function e(t){o(this,e),this.trackingHistory=[],this.subscribers=Object(i.a)(t),this.dispatch=this.dispatch.bind(this)}return u(e,[{key:"on",value:function(e,t){"function"==typeof t&&e&&"string"==typeof e&&(t.eventType=e,this.subscribers=[].concat(n(this.subscribers),[t]))}},{key:"dispatch",value:function(e){var t=e||{},r=t.type;if(!r)return null;for(var o=0;this.subscribers.length>o;o++)if("function"==typeof this.subscribers[o]&&this.subscribers[o].eventType===r){var i=this.subscribers[o].call(null,e,this.trackingHistory);i&&(this.trackingHistory=[].concat(n(this.trackingHistory),[i]))}}},{key:"getHistory",value:function(){return this.trackingHistory}}]),e}()}])});