0.12.0 • Published 5 years ago

react-spy v0.12.0

Weekly downloads
4
License
MIT
Repository
github
Last release
5 years ago

React Spy

A set of utilities for collecting UX-analytics of your React-application (ex: clicks, shows, errors and etc.)

npm i --save react-spy

Features

  • Easy integration with any ui-library (ex: Ant-Design)
  • Full control over the events

API


Usage

For example with Google Analytics

// Btn.js
import {spy} from 'react-spy';

const Btn = ({name, value}) => (<button name={name}>{value}</button>);
export default spy({
	id: ({name}) => name, // Computed `id` on based component properties
	listen: ['click'],    // DOM-events list
})(Btn);


// LoginForm.js
import {spy} from 'react-spy';

class LoginForm extends React.Component {
	// ...
	handleSubmit(evt) {
		evt.preventDefault();
		try {
			await api.login(this.getFormData());
			spy.send(this, 'success');
		} catch (err) {
			spy.send(this, 'failed', err);
		}
	}

	render() {
		return (
			<form onSubmit={this.handleEvent}>
				{/* ... */}
				<Btn name="login" value="Sign In"/>
				<Btn name="forgot" value="Forgot password"/>
			</form>
		);
	}
}

export default spy({
	id: "login-form",
	host: true,
	listen: ['mount', 'unmount'],
})(LoginForm);


// boot.js
import {addSpyObserver, addSpyErrorObserver} from 'react-spy';

addSpyObserver(chain => {
	// Send to GA
	ga('send', {
		hitType: 'event',
		eventCategory: chain[0], // ex: "login-form"
		eventAction: chain.slice(1).join('_'), // ex: "forgot_click"
	});
});

// Component Errors
addSpyErrorObserver(({error}) => {
	ga('send', 'exception', {
		exDescription: error.message,
		exFatal: false,
	});
});

ReactDOM.render(<App/>, document.body);

spy<Props>(options)

Decorate the component to collect analytics

  • options
    • id: string | (props, context?) => string — default @see propName description
    • propName: string — prop-name for id, by default spyId
    • listen: string[] — DOM-events to listen + error, mount and unmount
    • callbacks — list of observed callbacks that are passed to it via props
    • propName: string — name of the property responsible for the spy's id, by defaultspyId
    • host: boolean
import {spy} from 'react-spy';

export default spy({
	id: ({name}) => name,
	listen: ['click'],
})(function Btn({value}) {
	return <button>{value}</button>;
})

// Somewhere in the code
<Btn
	name="login"
	value="Sign in"
/>
// *click* -> ["login", "click"]

spy.send(cmp: React.Component, chain: string | string [], detail?: object): void

Send stats from the component and not only

  • cmp: React.Component — instance of React.Component
  • chain: string | string[] — name of metric
  • detail: object
import {spy} from 'react-spy';

export default spy({id: 'parent'})(class Box extends React.Component {
	render() {
		return (
			<button onClick={() => {spy.send(this, 'foo');}}>First</button>
			<button onClick={() => {spy.send(this, ['bar', 'baz'], {val: 123});}}>Second</button>
		);
	}
});

// Somewhere in a code
//   click on <First>:
//     - ["parent", "foo"] {}
//   click on <Second>:
//     - ["parent", "bar", "baz"] {val: 123}
//
// Somewhere in an another place:
//    spy.send(['global', 'label'], {time: 321}):
//      - ["global", "label"] {time: 321}

spy.error(cmp: React.Component, chain: string | string [], error: Error): void

send an error from the component and not only

  • cmp: React.Component — instance of React.Component
  • chain: string | string[] — name of metric
  • error: Error — any an error

addSpyObserver(fn: (chain: string[], detail: object) => void): UnsubsriberFn

Add observer of events for sending to the accounting system of analytics

import {addSpyObserver} from 'react-spy';

const unsubscribe = addSpyObserver(chain => {
	// Send to GA
	ga('send', {
		hitType: 'event',
		eventCategory: chain[0], // ex: "login-form"
		eventAction: chain.slice(1).join('_'), // ex: "forgot_click"
	});
});

// Somewhere (if you need to)
unsubscribe();

addSpyErrorObserver(fn: (detail: ErrorDetail) => void): UnsubsriberFn

Add observer of component errors

  • detail
    • error: Error — JavaScript error
    • info: object — React error info
    • chain string[] — spy id chain
import {addSpyErrorObserver} from 'react-spy';

addSpyErrorObserver(({error, chain}) => {
	// Send to GA
	ga('send', 'exception', {
		exDescription: error.message,
		exFatal: false,
	});

	// For dev
	console.error('[react-spy]', chain.join(' -> '));
	console.error(error);
});

intercept(rules: InterceptRules)

Intercepting a chain of events

import {intercept, UNCAUGHT} from 'react-spy';

intercept({
	'login-form': {
		// Interception of all chains, ex:
		//  - ["login-form", "forgot", "mount"]
		//  - ["login-form", "forgot", "click"]
		//  - etc
		'forgot'(send, chain, detail) {
			send(chain.concat('additional-id'));
		},

		// Processing of non-intercepted chains, ex:
		//  - ["login-form", "login", "click"]
		[UNCAUGHT](send, chain) {
			send(chain.concat('UNCAUGHT'));
			return false; // continue;
		}
	},
});

<Spy>...</Spy>

import {Spy} from 'react-spy';

const SomeFragment = ({condition, onShowDetail}) => (
	<div>
		<Spy id="top">
			<Button name="detail" value="Show detail" onClick={onShowDetail}/>
		</Spy>

		{condition &&
			<Spy id="bottom" listen={['mount', 'unmount'}>
				Detail
			</Spy>
		}
	</div>
);

// 1. *click on button* -> ["top", "detail", "click"]
// 2. *mounting* -> ["bottom", "mount"]

<SpyStep name="..."/>

The hidden spy element for steps monitoring

  • name: string — a step name
  • enter: string | string[] — the enter phase (optional)
  • leave: string | string[] — the leave phase (optional)

broadcast(chain: string[], detail?: object)

import {broadcast} from 'react-spy';

broadcast(['custom', 'event', 'chain'], {value: 'Wow'});
// or just
//   spy.send(['custom', 'event', 'chain'], {value: 'Wow'})

broadcastError(detail: ErrorDetail)

  • detail
    • error: Error — JavaScript error
    • chain string[] — spy id chain
    • info: object — React error info (optional)
import {broadcastError} from 'react-spy';

broadcastError({
	chain: ['login', 'submit', 'failed'],
	error: new Error('Internal Error'),
});
// or just
//   spy.error('localStorage', new Error('Read'));
//   spy.error(thisReactCmp, 'localStorage', new Error('save'));

Development

0.12.0

5 years ago

0.11.4

5 years ago

0.11.3

6 years ago

0.11.2

6 years ago

0.11.1

6 years ago

0.11.0

6 years ago

0.10.1

6 years ago

0.10.0

6 years ago

0.9.3

6 years ago

0.9.2

6 years ago

0.9.1

6 years ago

0.9.0

6 years ago

0.8.0

6 years ago

0.7.0

6 years ago

0.6.0

6 years ago

0.5.0

6 years ago

0.5.0-1

6 years ago

0.4.3-0

6 years ago

0.4.1-0

6 years ago

0.3.0

7 years ago

0.2.0

7 years ago

0.1.0

7 years ago

0.0.0

7 years ago