# Event Dispatcher Recipe

Here we will go through the steps to setup an Event Dispatcher component in your Nacelle + React project. This will help streamline the implementations of your analytics tools.

# Snippets

In order to make the Event Dispatcher available throughout the project, we are using React's Context API (opens new window).

In a providers directory, add a new EventDispatcher.js file:

import React, { useEffect, useReducer } from 'react'

export const EventLogContext = React.createContext()

const eventReducer = (state, event) => {
  if (
    event.type === 'PAGE_VIEW' ||
    event.type === 'PRODUCT_VIEW' ||
    event.type === 'ADD_TO_CART' ||
    event.type === 'REMOVE_FROM_CART' ||
    event.type === 'CHECKOUT_INIT'
  ) {
    return [...state, event]
  }
  return state
}

export const EventDispatcherProvider = ({ children }) => {
  const [eventLog, dispatchEvent] = useReducer(eventReducer, [])

  useEffect(() => {
    while (eventLog.length > 0 && typeof window !== 'undefined') {
      const event = eventLog.pop()
      switch (event.type) {
        case 'PAGE_VIEW':
          //Handle event here
          break
        case 'PRODUCT_VIEW':
          //Handle event here
          break
        case 'ADD_TO_CART':
          //Handle event here
          break
        case 'REMOVE_FROM_CART':
          //Handle event here
          break
        case 'CHECKOUT_INIT':
          //Handle event here
          break
        default:
          break
      }
    }
  }, [eventLog])

  return (
    <EventLogContext.Provider value={{ dispatchEvent }}>
      {children}
    </EventLogContext.Provider>
  )
}

By providing the dispatchEvent method to the rest of the of the project, this compoent will take in incoming events, will reduce (opens new window) them into an array of events and will handle each event as you see fit by executing your code everytime the eventLog value changes.

In order for the dispatchEvent method to be available in all your components you will also need to wrap the provider around the rest of your app, here is an example of it:

...
import { EventDispatcherProvider } from 'providers/EventDispatcher';
...

function MyApp({ Component, pageProps, space, products }) {
  return (
    <CartProvider useLocalStorage>
      <Global styles={styles.global} />
      <EventDispatcherProvider>
        <ProductSearchProvider products={products}>
          <Layout space={space}>
            <Component {...pageProps} />
          </Layout>
        </ProductSearchProvider>
      </EventDispatcherProvider>
    </CartProvider>
  )
}

Lastly you will need to call that dispatcher wherever you want to log a new event. Here is an example of how it would work on a product details page:

First import the dispatcher as well as the useContext & useEffect hooks:

import React, { useEffect, useContext } from 'react'
import { EventLogContext } from 'providers/EventDispatcher'

Then you will need to dispatch the event when the component mounts by passing it the event type and the necessary payload:

const { dispatchEvent } = useContext(EventLogContext)
useEffect(() => {
  dispatchEvent({ type: 'PRODUCT_VIEW', payload: product })
}, [])

Remember to follow the React rule of hooks (opens new window) and only call hooks at the top level.