Skip to content

Instantly share code, notes, and snippets.

@xdmorgan
Last active July 1, 2019 15:45
Show Gist options
  • Save xdmorgan/b94de9123503b86de13d02a2f00c734a to your computer and use it in GitHub Desktop.
Save xdmorgan/b94de9123503b86de13d02a2f00c734a to your computer and use it in GitHub Desktop.
React Hook / Google gtag event tracking / TypeScript / SSR-Friendly (tested with Gatsby)
/**
"Static Tracking" for values that will not change
```js
const [onTrack] = useStaticTracking({ category: 'Home Page', label: "Register" })
return <Button onClick={onTrack} />
```
"Dynamic Tracking" for values that will change between calls or vary in a loop
```js
const [onTrack] = useDynamicTracking({
action: 'View Profile',
category: 'Team Members',
})
// shared action and category with individual labels
people.map(person => <Button onClick={ () => onTrack({ label: person.name }) } /> )
```
Google gtag.js event tracking documentation:
https://developers.google.com/analytics/devguides/collection/gtagjs/events
*/
type obj = { [key: string]: string }
interface EventTrackingConfig {
command?: string
action?: string
category?: string
label?: string
value?: string
custom_options?: obj
}
type StaticTracker = () => any
type StaticSettings = {
debug: boolean
args: [string, string, obj]
}
type DynamicTracker = (config: EventTrackingConfig) => any
type DynamicSettings = { debug: boolean; shared: any }
// empty function for ssr case
const noop = () => {}
// create event tracking signature and return with the onClick
// handler from data provided to the hook at creation time
export function useStaticTracking(
config = {},
debug = false
): [StaticTracker, StaticSettings] {
const args = toArguments(config)
const settings = { debug, args }
// handle debug (console log), missing gtag global, and SSR case (no window)
const fn = debug ? console.info : canReportEvents() ? window.gtag : noop
return [() => fn(...args), settings]
}
// return event tracking function but handle config at call
// time for dynamic values that may change between calls
export function useDynamicTracking(
shared = {},
debug = false
): [DynamicTracker, DynamicSettings] {
const settings = { debug, shared }
// handle debug (console log), missing gtag global, and SSR case (no window)
const fn = debug ? console.info : canReportEvents() ? window.gtag : noop
return [current => fn(...toArguments({ ...shared, ...current })), settings]
}
// bail if ssr (no window) or gtag unavailble (localhost or misconfigured)
function canReportEvents() {
return typeof window !== 'undefined' && typeof window.gtag !== 'undefined'
}
// convert from config object to function signature
function toArguments({
command = 'event',
action = 'click',
category = undefined,
label = undefined,
value = undefined,
custom_options = undefined,
}: EventTrackingConfig): [string, string, obj] {
// should any options object be provided?
const empty = !(category || label || value || custom_options)
// create options object based on settings provided
const options = empty
? undefined
: {
...(category ? { event_category: category } : {}),
...(label ? { event_label: label } : {}),
...(value ? { value } : {}),
...custom_options,
}
return [command, action, options]
}
@xdmorgan
Copy link
Author

xdmorgan commented Jul 1, 2019

custom_options looks like a spread error 🤔

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment