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 ${(
Component Type Recommendation
Class components You have only the HOC option{' '} available.
Atlaskit function components Use{' '} usePlatformLeafEventHandler .
Other function components Use{' '} useCallbackWithAnalytics {' '} if you want something basic.
Use{' '} useAnalyticsEvents {' '} if you want more control.
)} ### 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; `} `;