import React from 'react';
import { code, md } from '@atlaskit/docs';
export default md`
This section will guide how to add analytics tracking to presentational and other
components that don't fit into the "Container" category.
For a conceptual overview of \`@atlaskit/analytics-next\`, please consult the
[concepts page](./concepts).
There are several ways to add analytics to a component, via React hooks, or
via higher order components (HOCs) - consult the Recommended Usage table for
our suggested approach.
## API
### Hooks API
* [\`useAnalyticsEvents\`](#use-analytics-events)
* [\`useCallbackWithAnalytics\`](#use-callback-with-analytics)
* [\`usePlatformLeafEventHandler\` and \`usePlatformLeafSyntheticEventHandler\`](#use-platform-leaf-event-handlers)
### HOCs API
* [\`withAnalyticsEvents\`](#with-analytics-events)
### Recommended Usage
${(
)}
### Examples
#### The \`useAnalyticsEvents\` hook
This custom React hook provides a method \`createAnalyticsEvent\` for creating \`UIAnalyticsEvent\`s.
${code`
import React, { useCallback } from 'react';
import { useAnalyticsEvents } from '@atlaskit/analytics-next';
const MyButton = ({ onClick = () => {} }) => {
const { createAnalyticsEvent } = useAnalyticsEvents();
const handler = useCallback((clickEvent) => {
const analyticsEvent = createAnalyticsEvent({
action: 'clicked',
componentName: 'my-button',
packageName: '@atlaskit/my-button',
packageVersion: '1.0.0'
});
// do what you like with the event, fire / modify / clone
// this here is the typical usage pattern for atlaskit components
const clonedEvent = analyticsEvent.clone();
analyticsEvent.fire("atlaskit");
// firing is prevented from happening more than once
// so that's why we pass a clone to be accessed by the parent component
// which might also want to fire their own event on this ui interaction
onClick(clickEvent, clonedEvent);
}, [ createAnalyticsEvent, onClick ]);
return (
);
}
export MyButton;
`}
#### The \`useCallbackWithAnalytics\` hook
This custom React hook takes a callback function and an event payload, and channel, and
returns a callback to fire the event and call the provided function.
The hooks stores the input and memoizes the return value to optimize performance.
${code`
import React, { useCallback } from 'react';
import { useCallbackWithAnalytics } from '@atlaskit/analytics-next';
const MyButton = ({ onClick = () => {} }) => {
const handler = useCallbackWithAnalytics(onClick, {
action: 'clicked',
componentName: 'my-button',
packageName: '@atlaskit/my-button',
packageVersion: '1.0.0'
}, 'atlaskit');
return (
);
}
export MyButton;
`}
#### The \`withAnalyticsEvents\` HOC
A HOC which provides the wrapped component with a method for creating \`UIAnalyticsEvent\`s,
via \`props.createAnalyticsEvent\`.
The HOC supports a few ways to use it for convinvience.
The first is to use the \`createAnalyticsEvent\` prop the HOC passes to the component manually:
${code`
import { withAnalyticsEvents } from '@atlaskit/analytics-next';
const MyButton = ({ onClick = () => {}, createAnalyticsEvent }) => {
const handler = (clickEvent) => {
const analyticsEvent = createAnalyticsEvent({
action: 'clicked',
componentName: 'my-button',
packageName: '@atlaskit/my-button',
packageVersion: '1.0.0'
});
// do what you like with the event, fire / modify / clone
// this here is the typical usage pattern for atlaskit components
const clonedEvent = analyticsEvent.clone();
analyticsEvent.fire("atlaskit");
// firing is prevented from happening more than once
// so that's why we pass a clone to be accessed by the parent component
// which might also want to fire their own event on this ui interaction
onClick(clickEvent, clonedEvent);
};
return (
);
}
const AnalyticsWrappedButton = withAnalyticsEvents()(MyButton);
export AnalyticsWrappedButton;
`}
Altenatively, the HOC accepts an optional map as its first argument, which provides a shortcut
for passing a new analytics event as an additional parameter to the corresponding callback prop.
${code`
import { withAnalyticsEvents } from '@atlaskit/analytics-next';
const MyButton = ({ onClick = () => {} }) => {
const handler = (clickEvent, analyticsEvent) => {
// do what you like with the event, fire / modify / clone
// this here is the typical usage pattern for atlaskit components
const clonedEvent = analyticsEvent.clone();
analyticsEvent.fire("atlaskit");
// firing is prevented from happening more than once
// so that's why we pass a clone to be accessed by the parent component
// which might also want to fire their own event on this ui interaction
onClick(clickEvent, clonedEvent);
};
return (
);
}
const AnalyticsWrappedButton = withAnalyticsEvents({
onClick: (createAnalyticsEvent) => createAnalyticsEvent({
action: 'clicked',
componentName: 'my-button',
packageName: '@atlaskit/my-button',
packageVersion: '1.0.0'
})
})(MyButton);
export AnalyticsWrappedButton;
`}
Since creating and returning an event is such a common pattern an even more concise shorthand is supported:
${code`
import { withAnalyticsEvents } from '@atlaskit/analytics-next';
const MyButton = ({ onClick = () => {} }) => {
const handler = (clickEvent, analyticsEvent) => {
// do what you like with the event, fire / modify / clone
// this here is the typical usage pattern for atlaskit components
const clonedEvent = analyticsEvent.clone();
analyticsEvent.fire("atlaskit");
// firing is prevented from happening more than once
// so that's why we pass a clone to be accessed by the parent component
// which might also want to fire their own event on this ui interaction
onClick(clickEvent, clonedEvent);
};
return (
);
}
const AnalyticsWrappedButton = withAnalyticsEvents({
onClick: {
action: 'clicked',
componentName: 'my-button',
packageName: '@atlaskit/my-button',
packageVersion: '1.0.0'
}
})(MyButton);
export AnalyticsWrappedButton;
`}
#### The \`usePlatformLeafEventHandler\` and \`usePlatformLeafSyntheticEventHandler\` hooks
These hooks were built with internal leaf node components purely in mind.
They dispatch an event on the \`atlaskit\` channel, then pass it to the
wrapped function as the last argument in case you want to something additional with the event.
\`usePlatformLeafEventHandler\` takes a function with two arguments (\`value\` and
\`analyticsEvent\`), while \`usePlatformLeafSyntheticEventHandler\` takes a function
with just one argument for the \`analyticsEvent\`
**WARNING:** *These hooks make an assumption that the component being wrapped is a "leaf-node"
component, i.e., they have no children that require analytics themselves. This
is so it can include the component name, package name, and package version as context
in the analytics event. It assumes no children need this context and makes no attempt to
pass it to them. This gains us a decent performance optimization. Use the other hooks
if you are unsure you can use these safely.*
${code`
import React, { useCallback } from 'react';
import {
usePlatformLeafEventHandler,
usePlatformLeafSyntheticEventHandler
} from '@atlaskit/analytics-next';
const MyButton = ({ onClick = () => {}, onActivate = () => {}}) => {
/**
* Event 1: usePlatformLeafEventHandler
*/
// this isn't necessary if you are happy with just firing on the 'atlaskit' channel
const wrapped = (clickEvent, analyticsEvent) => {
// do what you like with the event, fire / modify / clone
// this here is the typical usage pattern for atlaskit components
const clonedEvent = analyticsEvent.clone();
analyticsEvent.fire("otherChannel");
// firing is prevented from happening more than once
// so that's why we pass a clone to be accessed by the parent component
// which might also want to fire their own event on this ui interaction
onClick(clickEvent, clonedEvent);
};
const handler = usePlatformLeafEventHandler({
fn: wrapped, // use onClick instead if you want to just fire on 'atlaskit'
action: 'clicked',
componentName: 'my-button',
actionSubject : 'clickButton', // will use componentName as fallback if actionSubject is not passed
packageName: '@atlaskit/my-button',
packageVersion: '1.0.0',
analyticsData: {
// any additional data can live here
style: 'fancy'
},
});
/**
* Event 2: Synthetic event using usePlatformLeafSyntheticEventHandler
*/
const wrappedSynthetic = (analyticsEvent) => {
// A synthetic 'activate' event; same as above, but without a DOM event passed in
const clonedEvent = analyticsEvent.clone();
analyticsEvent.fire("otherChannel");
onActivate(clonedEvent);
};
const syntheticHandler = usePlatformLeafSyntheticEventHandler({
fn: wrappedSynthetic, // use onActivate instead if you want to just fire on 'atlaskit'
action: 'activated',
componentName: 'my-button',
packageName: '@atlaskit/my-button',
packageVersion: '1.0.0',
analyticsData: {
// any additional data can live here
style: 'fancy'
},
});
return (
// In this example the synthetic event is triggered by onFocus
);
}
export MyButton;
`}
`;