Skip to content

aimtbr/use-app-events

Repository files navigation

use-app-events

NPM Version NPM Unpacked Size Code test coverage Libraries.io dependency status for latest release

Create, trigger and listen for custom events in vanilla JavaScript and React.


📦 Small package (~19 kB)
🍃 Tree-shakeable
📝 Well documented
🛡️ Strictly typed with TypeScript
♻️ Events interact with each other across different browser tabs
⚛️ Exports a convenient hook for React developers


Examples

import { notifyEventListeners, listenForEvents } from 'use-app-events';

// 1. Listen for an event
listenForEvents('media-resume', () => {
  // do something when the event is emitted
});

// 2. Emit an event
notifyEventListeners('media-resume');

// 3. Listen for an event (it will only be processed once here)
listenForEvents.once('load-resource', async (url) => {
  await fetch(url);
});

// 4. Emit an event with some data
notifyEventListeners(
  'load-resource',
  'https://www.npmjs.com/package/use-app-events'
);

// 5. Listen for multiple events
const unlisten = listenForEvents(['event-1', 'event-2'], (eventType, url) => {
  if (eventType === 'event-1') {
    // do something when 'event-1' is emitted
  }

  if (eventType === 'event-2') {
    // do something when 'event-2' is emitted
  }
});

// 6. Stop listening for events
unlisten();

// 7. Emit multiple events with some data
notifyEventListeners(
  ['event-1', 'event-2'],
  'https://www.npmjs.com/package/use-app-events'
);

Install

npm

npm install use-app-events

pnpm

pnpm add use-app-events

Exports

  • notifyEventListeners
    • Function to notify all listeners of the specified event type(s) subscribed via listenForEvents.
  • listenForEvents
    • Function to subscribe and listen for the specified event type(s) to occur in the app.
  • listenForEvents.once
    • Function to subscribe and listen for the specified event type(s) to occur in the app once.
  • useAppEvents
    • Hook for managing application events in React.
  • heap
    • (readonly) Collection of resources operated by the package.
  • options
    • Collection of options used to adjust the behavior of the package.

How to use

  1. Listen for events in React

    import { useAppEvents } from 'use-app-events';

    a. Listen for an event

    const Component = () => {
      const { listenForEvents } = useAppEvents();
    
      listenForEvents('event-A', (payload) => {
        // 1. Do something when 'event-A' is triggered...
        // 2. Process a payload if you expect it to be sent by `notifyEventListeners`
      });
    };

    b. Listen for multiple events

    const Component = () => {
      const { listenForEvents } = useAppEvents();
    
      listenForEvents(['event-A', 'event-B'], (eventType, payload) => {
        // 1. Do something when either 'event-A' or 'event-B' is triggered...
    
        // 2. Process a specific event by its type in `eventType`
        if (eventType === 'event-A') {
          console.log('We got an event A with some data', payload);
        }
      });
    };
  2. Notify the event listeners in React

    a. Trigger an event

    const Component = () => {
      const { notifyEventListeners } = useAppEvents();
    
      // Notify the listeners of this event type with no data
      notifyEventListeners('event-A');
    };

    b. Trigger an event with some data

    const Component = () => {
      const { notifyEventListeners } = useAppEvents();
    
      const payload = { a: 1, b: 2 };
    
      // Notify the listeners of this event type and give them some data
      notifyEventListeners('event-A', payload);
    };

    c. Trigger multiple events with some data at once

    const Component = () => {
      const { notifyEventListeners } = useAppEvents();
    
      const payload = { a: 1, b: 2 };
    
      // Notify the listeners of these event types and give them some data
      notifyEventListeners(['event-A', 'event-B'], payload);
    };

    d. Trigger multiple events with some data, but don't broadcast

    const Component = () => {
      const { notifyEventListeners } = useAppEvents();
    
      const payload = { a: 1, b: 2 };
    
      // Notify the listeners of this event type in the current tab only
      notifyEventListeners('event-A', payload, false);
      // Notify the listeners of these event types in the current tab only
      notifyEventListeners(['event-B', 'event-C'], payload, false);
    };
  3. Adjust options

    import options from 'use-app-events/options';
    import notifyEventListeners from 'use-app-events/notifyEventListeners';

    a. Disable event broadcasting globally

    options.broadcast = false;
    
    // From now on, notifyEventListeners will send events to the listeners of the current tab only by default
    notifyEventListeners('event-A', 'some-payload');

    b. Enable the debug mode globally

    options.debug = true;
    
    // From now on, listenForEvents and notifyEventListeners will output additional console logs on different stages
    listenForEvents('event-A', () => {});
    notifyEventListeners('event-A', 'some-payload');

TypeScript

  • It is recommended to have a list of event types that can be used in your app, for example, enum called EventType, and pass it to useAppEvents() for type safety and misprint-proof: EventType passed to useAppEvents as a type


    This way you are protected from the unexpected event types...


    Unacceptable type passed as the event type to listenForEvents


    ...and only allowed to use the expected ones.


    The expected allowed event type passed to listenForEvents The expected allowed event type passed to notifyEventListeners


  • However, if EventType is not provided, any string or enum can be used: Plain string passed as the event type to listenForEvents and notifyEventListeners


Use cases


Examples

[See all examples]


API

Hook for managing application events in React.

useAppEvents<EventType extends string>(args): result
  - args?: {
      /** When true, enables a debug mode in non-production environment. */
      debug: boolean;
    }

  - result: {
      /** [Overload 1] Subscribe and listen for the specified event type to occur in the app. */
      function listenForEvents<Payload>(
        eventType: EventType,
        callback:
          | Callback<void>
          | Callback<Payload>
          | AsyncCallback<void>
          | AsyncCallback<Payload>
      ): CleanupFunction;

      /** [Overload 2] Subscribe and listen for the specified event types to occur in the app. */
      function listenForEvents<Payload>(
        eventTypes: EventType[],
        callback:
          | Callback<void>
          | Callback<Type>
          | Callback<[Type, Payload]>
          | AsyncCallback<void>
          | AsyncCallback<Type>
          | AsyncCallback<[Type, Payload]>
      ): CleanupFunction;

      /** [Overload 1] Notify all listeners of the specified event type subscribed via `listenForEvents`. */
      function notifyEventListeners<Payload>(
        /** Listeners of this event type will be notified. */
        eventType: EventType,
        /** Data to send to listeners of this event type. */
        payload?: Payload,
        /** When false, the event is not sent to other browsing contexts (tabs, windows). */
        broadcast?: boolean = options.broadcast
      ): void;

      /** [Overload 2] Notify all listeners of the specified event types subscribed via `listenForEvents`. */
      function notifyEventListeners<Payload>(
        /** Listeners of these event types will be notified. */
        eventTypes: EventType[],
        /** Data to send to listeners of these event types. */
        payload?: Payload,
        /** When false, the event is not sent to other browsing contexts (tabs, windows). */
        broadcast?: boolean = options.broadcast
      ): void;
    }

The notifyEventListeners and listenForEvents functions are also available independently outside of the useAppEvents hook to be used beyond the React components/hooks.

However, prefer useAppEvents in React when possible.


Collection of resources operated by the package.

heap: {
  /** The array of listeners used by the active `listenForEvents` instances. */
  eventListeners: Listener[];
}

Collection of options used to adjust the behavior of the package.

options: {
  /** When false, `notifyEventListeners` will not broadcast events to other browsing contexts (tabs, windows) by default. */
  broadcast: boolean = true;

  /** When true, the debug mode will be enabled globally, resulting in additional logs. */
  debug: boolean = false;
}

Motivation

The motivation to create use-app-events was to find a way to manage the state from any part of the app (globally) and allow all elements to communicate with each other regardless of their position in the tree.


Try it yourself

Clone the repository, install dependencies, and run the dev script to start a web app and play around with examples.

pnpm

git clone https://github.com/aimtbr/use-app-events.git && cd use-app-events && pnpm install && pnpm dev

npm

git clone https://github.com/aimtbr/use-app-events.git && cd use-app-events && npm install && npm run dev

License

MIT

Author

Maksym Marchuk

About

Create, trigger and listen for custom events in vanilla JavaScript and React.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published