React-Spy-API

React Spy API For React Application ( Spy error, Intercept, BrodcastError etc...)

View on GitHub

React Spy API

React Spy API For React Application ( Spy error, Intercept, BrodcastError etc…)

npm i --save react-spy

Features


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

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

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


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

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


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)

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